package dev.banking.model; public class BankAccount { private final int accountId; private long balance; private final ReentrantLock lock = new ReentrantLock(); /* * Students may introduce additional fields * such as: * - Lock / ReentrantLock * - ReadWriteLock * - Object monitor * - etc. */ public BankAccount(int accountId, long initialBalance) { this.accountId = accountId; this.balance = initialBalance; } public int getAccountId() { 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() { lock.lock(); try{ return balance; }finally { lock.unlock(); } } /* * TODO: * Increase balance atomically. * * Requirements: * - Must not lose updates under concurrency */ public void deposit(long amount) { lock.lock(); try{ balance+=amount; }finally { lock.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) { lock.lock(); try{ balance-=amount; }finally { lock.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) { BankAccount first; BankAccount second; if (this == target) { return; } if (this.getAccountId() < target.getAccountId()) { first = this; second = target; } else { first = target; second = this; } first.lock.lock(); try { second.lock.lock(); try { this.balance -= amount; target.balance += amount; } finally { second.lock.unlock(); } } finally { first.lock.unlock(); } } }