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());
}
}
@jsampson
Copy link

No, I should have said more strongly: ConcurrentModificationException is not intended for detecting modification by different threads. If two different threads attempt to add to an unsynchronized ArrayList, anything can happen. One or the other thing might be added, one or the other might fail with some runtime exception, one or the other could hang in an infinite loop. You can't count on any particular behavior with unsynchronized data structures accessed by multiple threads.

@felipecruz
Copy link
Author

ok.. you're right about concurrent modification exception.. http://download.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html

but same thing would be possible with a immutable list (http://functionaljava.org/) and AtomicReference.. or with an atomic integer counting writes and evaluation loop (ammount_now()) checking this counter,, right? if it's dirty, try again..

do you think that those approaches are broken?

@felipecruz
Copy link
Author

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