diff --git a/src/main/java/dev/banking/model/BankAccount.java b/src/main/java/dev/banking/model/BankAccount.java index 745ede2..ea92f44 100644 --- a/src/main/java/dev/banking/model/BankAccount.java +++ b/src/main/java/dev/banking/model/BankAccount.java @@ -1,10 +1,18 @@ package dev.banking.model; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + public class BankAccount { + + private final int accountId; private long balance; - + private Lock accountLock = new ReentrantLock(); + private Condition accountCon = accountLock.newCondition(); /* * Students may introduce additional fields * such as: @@ -23,56 +31,78 @@ public class BankAccount { return accountId; } - /* - * TODO: - * Return the current balance in a thread-safe way. - * - * Requirements: - * - Must be safe under concurrent reads/writes - * - Should not block unnecessarily if using read/write locks - */ public long getBalance() { - throw new UnsupportedOperationException("TODO: implement thread-safe balance read"); + accountLock.lock(); + try{ + return this.balance; + }finally { + accountLock.unlock(); + } } - /* - * TODO: - * Increase balance atomically. - * - * Requirements: - * - Must not lose updates under concurrency - */ + public void deposit(long amount) { - throw new UnsupportedOperationException("TODO: implement thread-safe deposit"); + accountLock.lock(); + try{ + balance += amount; + accountCon.signalAll(); + }finally { + accountLock.unlock(); + } } - /* - * TODO: - * Decrease balance atomically. - * - * Requirements: - * - Must not cause race conditions - * - Negative balance handling is NOT required unless you decide - * to extend the system (optional) - */ public void withdraw(long amount) { - throw new UnsupportedOperationException("TODO: implement thread-safe withdraw"); + accountLock.lock(); + try{ + while (balance < amount){ + accountCon.await(); + } + balance -= amount; + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + accountLock.unlock(); + } + } - /* - * TODO: - * Transfer money between two accounts atomically. - * - * IMPORTANT REQUIREMENTS: - * - Must be atomic (no partial transfer) - * - Must be deadlock-free - * - Must protect both source and target accounts - * - * HINT: - * - Consider global lock ordering using accountId - * - Or tryLock with retry strategy - */ + public void transfer(BankAccount target, long amount) { - throw new UnsupportedOperationException("TODO: implement atomic deadlock-free transfer"); + + if(this.getAccountId() == target.getAccountId()){ + return; + } + + BankAccount first = this.getAccountId() < target.getAccountId() ? this : target; + BankAccount second = this.getAccountId() < target.getAccountId() ? target : this; + + + first.accountLock.lock(); + + try { + + second.accountLock.lock(); + try { + + while (this.balance < amount) { + this.accountCon.await(); + } + this.balance -= amount; + target.balance += amount; + + this.accountCon.signalAll(); + + }catch (InterruptedException e){ + throw new RuntimeException(); + }finally { + second.accountLock.unlock(); + } + + + + }finally { + first.accountLock.unlock(); + } + } } \ No newline at end of file