The account problem in Java and Clojure

1,418 views

Published on

This presentation shows how bad Java is at handling concurrency, and how good Clojure is at handling the same problem.

Published in: Technology
  • Be the first to comment

The account problem in Java and Clojure

  1. 1. The account problem in Java and Clojure Alf Kristian Støyle
  2. 2. public class Account { private long balance; private final int accountNo; public void debit(long debitAmount) { this.balance -= debitAmount; } public void credit(long creditAmount) { this.balance += creditAmount; } public long getBalance() { return this.balance; } public void getAccountNo() { return this.accountNo; } }
  3. 3. public class Account { private volatile long balance; private final int accountNo; public synchronized void debit(long debitAmount) { this.balance -= debitAmount; } public synchronized void credit(long creditAmount) { this.balance += creditAmount; } public synchronized long getBalance() { return this.balance; } public void getAccountNo() { return this.accountNo; } }
  4. 4. public void transfer(Account fromAccount, Account toAccount, long amount) throws Exception { if (fromAccount.getBalance() < amount) { throw new Exception("Not enough money!"); } fromAccount.debit(amount); toAccount.credit(amount); }
  5. 5. public void transfer(Account fromAccount, Account toAccount, long amount) throws Exception { synchronized (fromAccount) { synchronized (toAccount) { if (fromAccount.getBalance() < amount) { throw new Exception("Not enough money!"); } fromAccount.debit(amount); toAccount.credit(amount); } } }
  6. 6. public void transfer(Account fromAccount, Account toAccount, long amount) throws Exception { Object mutex1 = toAccount; Object mutex2 = fromAccount; if (fromAccount.getAccountNo() > toAccount.getAccountNo()) { mutex1 = fromAccount; mutex2 = toAccount; } synchronized (mutex1) { synchronized (mutex2) { if (fromAccount.getBalance() < amount) { throw new Exception("Not enough money!"); } fromAccount.debit(amount); toAccount.credit(amount); } } }
  7. 7. public class Account { private volatile long balance; private final int accountNo; public synchronized void debit(long debitAmount) { this.balance -= debitAmount; } public synchronized void credit(long creditAmount) { this.balance += creditAmount; } public synchronized long getBalance() { return this.balance; } public void getAccountNo() { return this.accountNo; } } public void transfer(Account fromAccount, Account toAccount, long amount) throws Exception { Object mutex1 = toAccount; Object mutex2 = fromAccount; if (fromAccount.getAccountNo() > toAccount.getAccountNo()) { mutex1 = fromAccount; mutex2 = toAccount; } synchronized (mutex1) { synchronized (mutex2) { if (fromAccount.getBalance() < amount) { throw new Exception("Not enough money!"); } fromAccount.debit(amount); toAccount.credit(amount); } } }
  8. 8. Clojure
  9. 9. Clojure • Pure functional
  10. 10. Clojure • Pure functional • Managed references • Ref • ...
  11. 11. Clojure • Pure functional • Managed references • Ref • ... • Software transactional memory
  12. 12. (defn transfer [from-account to-account amount] (dosync (if (> amount @from-account) (throw (Exception. "Not enough money!"))) (alter from-account - amount) (alter to-account + amount)))
  13. 13. (defn transfer [from-account to-account amount] (dosync (if (> amount @from-account) (throw (Exception. "Not enough money!"))) (alter from-account - amount) (alter to-account + amount))) OMG it’s a Lisp!
  14. 14. (defn transfer [from-account to-account amount] (dosync (if (> amount @from-account) (throw (Exception. "Not enough money!"))) (alter from-account - amount) (alter to-account + amount)))
  15. 15. (defn transfer [from-account to-account amount] (dosync (if (> amount @from-account) (throw (Exception. "Not enough money!"))) (alter from-account - amount) (alter to-account + amount))) (def account-a (ref 1000)) (def account-b (ref 800))
  16. 16. (defn transfer [from-account to-account amount] (dosync (if (> amount @from-account) (throw (Exception. "Not enough money!"))) (alter from-account - amount) (alter to-account + amount))) (def account-a (ref 1000)) (def account-b (ref 800)) (transfer account-a account-b 300) @account-a => 700
  17. 17. (defn transfer [from-account to-account amount] (dosync (if (> amount @from-account) (throw (Exception. "Not enough money!"))) (alter from-account - amount) (alter to-account + amount))) (def account-a (ref 1000)) (def account-b (ref 800)) (alter account-a - 100) => java.lang.IllegalStateException: No transaction running
  18. 18. The pragmatic programmers “Learn at least one new language every year”

×