diff --git a/src/main/java/dev/banking/model/BankAccount.java b/src/main/java/dev/banking/model/BankAccount.java index 745ede2..a179dc3 100644 --- a/src/main/java/dev/banking/model/BankAccount.java +++ b/src/main/java/dev/banking/model/BankAccount.java @@ -1,10 +1,16 @@ package dev.banking.model; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + public class BankAccount { private final int accountId; private long balance; + private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + /* * Students may introduce additional fields * such as: @@ -32,7 +38,12 @@ public class BankAccount { * - Should not block unnecessarily if using read/write locks */ public long getBalance() { - throw new UnsupportedOperationException("TODO: implement thread-safe balance read"); + lock.readLock().lock(); + try { + return balance; + } finally { + lock.readLock().unlock(); + } } /* @@ -43,7 +54,15 @@ public class BankAccount { * - Must not lose updates under concurrency */ public void deposit(long amount) { - throw new UnsupportedOperationException("TODO: implement thread-safe deposit"); + if(amount < 0) + throw new IllegalArgumentException("Amount can't be negative!"); + + lock.writeLock().lock(); + try { + balance += amount; + } finally { + lock.writeLock().unlock(); + } } /* @@ -56,7 +75,15 @@ public class BankAccount { * to extend the system (optional) */ public void withdraw(long amount) { - throw new UnsupportedOperationException("TODO: implement thread-safe withdraw"); + if(amount < 0) + throw new IllegalArgumentException("Amount can't be negative!"); + + lock.writeLock().lock(); + try { + balance -= amount; + } finally { + lock.writeLock().unlock(); + } } /* @@ -73,6 +100,28 @@ public class BankAccount { * - Or tryLock with retry strategy */ public void transfer(BankAccount target, long amount) { - throw new UnsupportedOperationException("TODO: implement atomic deadlock-free transfer"); + if (amount < 0) { + throw new IllegalArgumentException("Transfer amount cannot be negative"); + } + if (this == target) { + throw new IllegalArgumentException("Cannot transfer to the same account"); + } + + // we order them by their id so that we always lock the first one to prevent deadLocks taking place. + BankAccount first = this.accountId < target.accountId ? this : target; + BankAccount second = this.accountId < target.accountId ? target : first; + + first.lock.writeLock().lock(); + try { + second.lock.writeLock().lock(); + try { + this.balance -= amount; + target.balance += amount; + } finally { + second.lock.writeLock().unlock(); + } + } finally { + first.lock.writeLock().unlock(); + } } } \ No newline at end of file