diff --git a/Answers.md b/Answers.md new file mode 100644 index 0000000..3423855 --- /dev/null +++ b/Answers.md @@ -0,0 +1,44 @@ +# Answers + +## Question 1 + +Atomic variables are thread-safe variables provided by Java. + +They allow multiple threads to update a value safely without using synchronized blocks or locks. + +Regular variables do not provide this protection and may cause race conditions. + +## Question 2 + +Four classes from the `java.util.concurrent.atomic` package are: + +- AtomicInteger +- AtomicLong +- AtomicBoolean +- AtomicReference + +`AtomicInteger` is used for thread-safe integer operations such as incrementing or decrementing a counter. + +## Question 3 + +Atomic variables are useful for simple operations on a single variable. + +For more complex operations involving multiple variables or multiple steps, locks are usually a better choice. + +## Question 4 + +Yes. A program can be free of race conditions but still have poor performance. + +Too much synchronization, lock contention, and thread management overhead can slow down the program. + +## Question 5 + +Adding more threads does not always improve performance because threads compete for CPU time and shared resources. + +In some cases, too many threads can actually reduce performance. + +## Question 6 + +Deadlocks are difficult to detect because they depend on thread scheduling. + +A program may work correctly many times and then suddenly deadlock under different execution conditions. \ No newline at end of file diff --git a/src/main/java/dev/banking/model/BankAccount.java b/src/main/java/dev/banking/model/BankAccount.java index 745ede2..cd93593 100644 --- a/src/main/java/dev/banking/model/BankAccount.java +++ b/src/main/java/dev/banking/model/BankAccount.java @@ -1,18 +1,13 @@ package dev.banking.model; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + public class BankAccount { private final int accountId; private long balance; - - /* - * Students may introduce additional fields - * such as: - * - Lock / ReentrantLock - * - ReadWriteLock - * - Object monitor - * - etc. - */ + private final Lock lock = new ReentrantLock(); public BankAccount(int accountId, long initialBalance) { this.accountId = accountId; @@ -23,56 +18,58 @@ 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"); + lock.lock(); + try { + return balance; + } finally { + lock.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"); + 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) { - throw new UnsupportedOperationException("TODO: implement thread-safe withdraw"); + 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) { - throw new UnsupportedOperationException("TODO: implement atomic deadlock-free transfer"); + if (target == this) { + return; + } + + BankAccount first; + BankAccount second; + + if (this.accountId < target.accountId) { + first = this; + second = target; + } else { + first = target; + second = this; + } + + first.lock.lock(); + second.lock.lock(); + + try { + this.balance -= amount; + target.balance += amount; + } finally { + second.lock.unlock(); + first.lock.unlock(); + } } } \ No newline at end of file