package dev.banking.model; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class BankAccount { private final int accountId; private long balance; private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); private final ReentrantLock transferLock = 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() { rwLock.readLock().lock(); try { return balance; } finally { rwLock.readLock().unlock(); } } /* * TODO: * Increase balance atomically. * * Requirements: * - Must not lose updates under concurrency */ public void deposit(long amount) { rwLock.writeLock().lock(); try { balance += amount; } finally { rwLock.writeLock().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) { rwLock.writeLock().lock(); try { balance -= amount; } finally { rwLock.writeLock().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.getAccountId() < target.getAccountId()) { first = this; second = target; } else { first = target; second = this; } first.transferLock.lock(); try { second.transferLock.lock(); try { first.balance -= amount; target.balance += amount; } finally { second.transferLock.unlock(); } } finally { first.transferLock.unlock(); } } }