From b4af6880fe91939dbc62ad16de1a8511bdef0b54 Mon Sep 17 00:00:00 2001 From: Fateme Azizi Date: Sun, 14 Jun 2026 20:14:13 +0330 Subject: [PATCH 1/3] add Answers.md --- Answers.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Answers.md diff --git a/Answers.md b/Answers.md new file mode 100644 index 0000000..e69de29 -- 2.54.0 From 69620f3e5581218b8baa8cb85478c8682aa6f14c Mon Sep 17 00:00:00 2001 From: Fateme Azizi Date: Mon, 15 Jun 2026 02:32:34 +0330 Subject: [PATCH 2/3] implement Answers.md --- Answers.md | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/Answers.md b/Answers.md index e69de29..b4221cc 100644 --- a/Answers.md +++ b/Answers.md @@ -0,0 +1,97 @@ +## Question 1 +An **atomic variable** is a special type of variable that performs operations + +The purpose of using them is to prevent **race conditions** + +- **Atomic variables**: thread-safe for simple operations (like increment, update). + +- **Ordinary variables**: can cause race conditions if multiple threads change them together without protection. + +## Question 2 + +Examples of classes in java.util.concurrent.atomic: + +1. AtomicInteger +2. AtomicLong +3. AtomicBoolean +4. AtomicReference + +AtomicInteger: +Used as a thread-safe counter. For example, in a multithreaded server, multiple threads can increase the number of requests safely without using synchronized. + +## Question 3 + +Atomic variables: It's better for simple operations on a single value (increment, update, compare-and-set). +They are usually faster and lighter because they avoid blocking threads. + +Locks: Used when multiple operations must happen together. Threads wait until the lock is released. + + +Use a lock when: + +- Multiple variables must stay consistent together + +- A complex sequence of actions must be protected + +- You need critical sections with more control + + +Use an atomic variable when: + +- Only one variable is shared + +- Operations are simple (counter) + +- High performance and low overhead are important + + +## Question 4 + +A program can be free of race conditions but still be slow under high contention because correctness does not mean good performance. +Threads may work safely but spend time waiting instead of doing useful work. + +Three factors that limit scalability: + +1. Lock Contention + Many threads try to access the same lock. Only one can continue, so others wait, reducing parallelism. + + +2. Context Switching + The CPU constantly switches between threads. Frequent switching adds overhead and wastes time. + + +3. Synchronization Overhead + Operations like locks, atomic updates, and coordination between threads require extra CPU work and memory synchronization. + + +## Question 5 + +Adding more threads does not always improve performance because after a certain point, threads start spending more time coordinating and competing than doing actual work. + +1. When there are too many threads, the CPU frequently switches between them. +Saving and restoring thread states creates overhead and reduces efficiency. + + +2. Multiple threads may compete for the same resources (locks, memory, shared data). Some threads must wait, so parallel execution decreases. + + +3. Each CPU core has its own cache. When several threads modify shared data, caches must stay synchronized, +creating extra communication and slowing execution. + + +4. Locks, atomic operations, and coordination mechanisms require additional processing time to maintain correctness. + + +## Question 6 + +Deadlocks often appear in production but not during testing. During testing, threads may run in a favorable order and +never reach the lock sequence that causes deadlock. In production, different timing, higher load, and more threads can create the exact conditions needed. + +Two strategies to expose deadlocks during testing: + +1. Stress / Load Testing + Run the program with many threads, repeated executions, and high concurrency to increase the chance of problems. + + +2. Introduce Scheduling Variations + Add random delays, sleeps, or use concurrency testing tools to force different execution orders and increase the probability of triggering deadlocks. -- 2.54.0 From ed4473a23931e5809e5455f598c49ae842f67479 Mon Sep 17 00:00:00 2001 From: Fateme Azizi Date: Mon, 15 Jun 2026 17:12:58 +0330 Subject: [PATCH 3/3] implement BankAccount.java --- .../java/dev/banking/model/BankAccount.java | 63 ++++++++++++++----- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/src/main/java/dev/banking/model/BankAccount.java b/src/main/java/dev/banking/model/BankAccount.java index 745ede2..746f73d 100644 --- a/src/main/java/dev/banking/model/BankAccount.java +++ b/src/main/java/dev/banking/model/BankAccount.java @@ -1,9 +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; + private Lock lock = new ReentrantLock(); /* * Students may introduce additional fields @@ -23,44 +27,44 @@ public class BankAccount { return accountId; } - /* - * TODO: - * Return the current balance in a thread-safe way. + /* 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. + /* Increase balance atomically. * * Requirements: * - Must not lose updates under concurrency */ - public void deposit(long amount) { - throw new UnsupportedOperationException("TODO: implement thread-safe deposit"); + public synchronized void deposit(long amount) { + balance += amount; } - /* - * TODO: - * Decrease balance atomically. + /* 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"); + public synchronized void withdraw(long amount) { + balance -= amount; } /* - * TODO: * Transfer money between two accounts atomically. * * IMPORTANT REQUIREMENTS: @@ -73,6 +77,33 @@ public class BankAccount { * - Or tryLock with retry strategy */ public void transfer(BankAccount target, long amount) { - throw new UnsupportedOperationException("TODO: implement atomic deadlock-free transfer"); + + BankAccount first, second; + + if(target == this) return; + + if (this.getAccountId() < target.getAccountId()) { + first = this; + second = target; + } + else { + first = target; + second = this; + } + + first.lock.lock(); + try { + second.lock.lock(); + try { + this.withdraw(amount); + target.deposit(amount); + } + finally { + second.lock.unlock(); + } + } + finally { + first.lock.unlock(); + } } } \ No newline at end of file -- 2.54.0