From 31a4b18ce7f7526279d740810e99442c317fa1eb Mon Sep 17 00:00:00 2001 From: Amir mohammad Date: Wed, 17 Jun 2026 14:27:02 +0330 Subject: [PATCH 1/2] Implement thread-safe BankAccount operations --- .idea/.gitignore | 10 ++ .idea/compiler.xml | 13 +++ .idea/encodings.xml | 7 ++ .idea/jarRepositories.xml | 20 ++++ .idea/misc.xml | 12 +++ .idea/vcs.xml | 6 ++ Answer.md | 0 .../java/dev/banking/model/BankAccount.java | 99 +++++++++---------- 8 files changed, 117 insertions(+), 50 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml create mode 100644 Answer.md diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..812c3f9 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..4158879 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..eba6e1f --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Answer.md b/Answer.md new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/dev/banking/model/BankAccount.java b/src/main/java/dev/banking/model/BankAccount.java index 745ede2..f8a4b72 100644 --- a/src/main/java/dev/banking/model/BankAccount.java +++ b/src/main/java/dev/banking/model/BankAccount.java @@ -1,18 +1,12 @@ package dev.banking.model; +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 ReentrantLock lock = new ReentrantLock(); public BankAccount(int accountId, long initialBalance) { this.accountId = accountId; @@ -23,56 +17,61 @@ 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"); + 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 -- 2.54.0 From 9741482f27d5b2d174d830461abcb53389de9e73 Mon Sep 17 00:00:00 2001 From: Amir mohammad Date: Wed, 24 Jun 2026 07:20:37 +0330 Subject: [PATCH 2/2] Update Answer.md --- Answer.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/Answer.md b/Answer.md index e69de29..2332841 100644 --- a/Answer.md +++ b/Answer.md @@ -0,0 +1,73 @@ +## Question 1 + + +1 - What are atomic variables? + +Atomic variables are variables that provide thread-safe operations without using explicit locks. Operations such as incrementing or updating a value are performed atomically, meaning they cannot be interrupted by other threads. + +Ordinary variables do not provide this guarantee. For example, the expression `counter++` consists of multiple steps, and different threads may interfere with each other, causing race conditions. + +Atomic variables are mainly used to safely share data between multiple threads. + +## Question 2 + +2 - Name at least four classes from the java.util.concurrent.atomic package that provide atomic operations for different data types. + +Some classes from the `java.util.concurrent.atomic` package are: + +- AtomicInteger +- AtomicLong +- AtomicBoolean +- AtomicReference + +A common use case for `AtomicInteger` is a shared counter. Multiple threads can safely increment the counter without using locks. + +## Question 3 + +3 - Compare locks with atomic variables. + +Atomic variables are usually faster and simpler for operations on a single variable. They have lower overhead and do not require explicit locking. + +Locks are better when multiple operations or multiple shared variables must be protected together. They provide more flexibility but usually have higher overhead. + +Use atomic variables for simple updates such as counters. Use locks for complex critical sections that involve several operations. + +## Question 4 + +4 - A program is completely free of race conditions but still performs poorly under high contention. + +A program can be free of race conditions and still perform poorly because correctness does not guarantee scalability. + +Some factors that limit performance are: + +1. Lock contention, where many threads wait for the same lock. +2. Thread blocking, which reduces parallel execution. +3. Synchronization overhead, which adds extra work for coordinating threads. + +As a result, the program remains correct but may not scale well under heavy load. + +## Question 5 + +5 - Many concurrent systems experience performance degradation as the number of threads increases. + +Adding more threads does not always improve performance. + +- Context switching takes CPU time when the operating system switches between threads. +- Contention happens when many threads compete for the same resources. +- Cache coherence creates extra work for processors to keep shared data consistent. +- Synchronization overhead increases because locks and coordination mechanisms require additional processing. + +Because of these costs, too many threads can actually reduce performance. + +## Question 6 + +6 - Deadlocks often only appear in production, not during testing. + +Deadlocks often depend on specific thread schedules. During testing, the required scheduling order may never occur. In production, higher load and different timing make deadlocks more likely. + +Two ways to expose deadlocks during testing are: + +1. Stress testing with many threads and repeated executions. +2. Adding random delays to create different thread interleavings. + +These techniques increase the chance of reproducing deadlock situations before deployment. \ No newline at end of file -- 2.54.0