Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save felipecruz/1233217 to your computer and use it in GitHub Desktop.
Save felipecruz/1233217 to your computer and use it in GitHub Desktop.
can_you_lead_account_current_ammount_to_inconsistency.java
public class LiveBank implements Serializable{
private Map<Integer, Account> accounts;
private AtomicInteger next_account_number = new AtomicInteger(0);
public LiveBank() {
this.accounts = new HashMap<Integer, Account>(); // concurrent hashmap maybe
}
public Account createAccount() {
int id = this.next_account_number.incrementAndGet();
Account account = new Account(id);
this.accounts.put(new Integer(id), account);
return account;
}
public Account getAccount(Integer id) {
return this.accounts.get(id);
}
public void deposit(int id, int ammount) {
// can collection .add throw ConcurrentModificationException?
// no.. it will not throw
getAccount(id).append_transaction(new Deposit(ammount));
}
public void withdraw(int id, int ammount) {
// can collection .add throw ConcurrentModificationException?
// no it will not throw
getAccount(id).append_transaction(new Withdraw(ammount));
}
}
public interface BankTransaction {
public int apply(int ammount);
}
public class Withdraw implements BankTransaction {
public int ammount;
public Withdraw(int ammount) {
this.ammount = ammount;
}
@Override
public int apply(int ammount) {
ammount -= this.ammount;
return ammount;
}
}
public class Deposit implements BankTransaction {
public int ammount;
public Deposit(int ammount) {
this.ammount = ammount;
}
@Override
public int apply(int ammount) {
ammount += this.ammount;
return ammount;
}
}
public class Account implements Serializable {
public int id;
public Collection<BankTransaction> transactions;
public int ammount = 0;
public Account(int id) {
this.id = id;
// alternatives:
// Vector or Collections.synchronizedList
// or (and i think(we need to test) this is the best option)
// CopyOnWriteArrayList
// http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html
this.transactions = new ArrayList<BankTransaction>();
}
public append_transaction(Transaction transaction) {
// check atomic_write_counter
// increment_atomic_write_counter
// collection.append
// decrement write counter
}
//instead of locking, why not retry? optimistic design
public int ammount_now() {
int local_ammount = 0;
//try {
for(BankTransaction transaction : this.transactions) {
local_ammount = transaction.apply(local_ammount);
Cool.sleep(3); //do not use this on production :)
if (atomic_write_count > 0) { /* try again since someone is writing */ }
}
//}
/* maybe a retry loop
catch (ConcurrentModificationException ce) {
System.out.println("write fucked read");
// recursive call cause I'm lazy.. is this naive?
local_ammount = this.ammount_now();
} */
return local_ammount;
}
}
public class LiveBankTest {
public static void main(String[] args) {
final LiveBank bank = new LiveBank();
final Account account = bank.createAccount();
Thread t = new Thread(new MyRunnable(bank, account));
t.start();
System.out.println(account.id);
bank.deposit(account.id, 100);
System.out.println(account.ammount_now());
bank.withdraw(account.id, 50);
for (int i = 0; i < 1000; i++) {
System.out.println(i + " - " + account.ammount_now());
Cool.sleep(20);
}
}
}
class MyRunnable implements Runnable {
private LiveBank bank2;
private Account account2;
public MyRunnable(LiveBank bank, Account account) {
this.account2 = account;
this.bank2 = bank;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
bank2.deposit(account2.id, 100);
System.out.println("more 100");
org.prevayler.foundation.Cool.sleep(1000);
}
System.out.println(account2.ammount_now());
}
}
@felipecruz
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment