From f40f6e3bdcbb3b240598faf1b5a113a232ad8e15 Mon Sep 17 00:00:00 2001 From: SoroushZ Date: Fri, 3 Jul 2026 22:42:53 +0330 Subject: [PATCH] 9 --- .idea/.gitignore | 10 ++ .idea/compiler.xml | 13 +++ .idea/encodings.xml | 7 ++ .idea/jarRepositories.xml | 20 ++++ .idea/misc.xml | 12 +++ .idea/vcs.xml | 6 ++ Anss.md | 42 +++++++++ .../java/dev/banking/model/BankAccount.java | 94 +++++++++---------- 8 files changed, 153 insertions(+), 51 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 Anss.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..712ab9d --- /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..5e4e294 --- /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/Anss.md b/Anss.md new file mode 100644 index 0000000..f3245a0 --- /dev/null +++ b/Anss.md @@ -0,0 +1,42 @@ +⚛️ Atomic Variables & Synchronization + +**1. What are atomic variables?** + +Atomic variables are essentially variables that allow us to perform thread-safe operations without explicitly using locks (like *synchronized*). When I use an atomic variable, the operation (like read-modify-write) is done in a single, indivisible hardware step (using CAS - Compare-And-Swap). This is different from ordinary variables where an operation like `count++` actually takes three steps (read, increment, write) and can get interrupted by other threads, leading to race conditions. + +**2. Name at least four classes from the java.util.concurrent.atomic package that provide atomic operations for different data types** +*AtomicInteger* +*AtomicLong* +*AtomicBoolean* +*AtomicReference* + +**Use case:** I usually use `AtomicInteger` when I need a simple counter in a web server or an application to keep track of concurrent requests or active users. It's much faster than wrapping an `int` inside a `synchronized` block. + +**3. Compare locks with atomic variables.** +- **Atomic variables** are a better choice when I only need to update a *single* variable or flag independently (like a counter). They have less overhead because they don't block threads. +- **Locks** are necessary when my logic involves updating *multiple* variables at the same time that depend on each other, or when I need to protect a complex critical section of code. + + +🔒 Locks & Concurrent Design + +**4. A program is completely free of race conditions but still performs poorly under high contention.** + +Even if my code has zero race conditions, it can still run slowly due to: +1. **High Contention:** If all my threads are constantly trying to acquire the same lock, most of them will just be waiting in a queue doing nothing. +2. **Coarse-grained locking:** If I lock an entire large method instead of just the critical section, I limit concurrency unnecessarily. +3. **Context Switching Overhead:** The OS wastes a lot of CPU cycles switching between threads that are constantly pausing and waking up to check locks. + +**5. Many concurrent systems experience performance degradation as the number of threads increases.** + +Adding threads doesn't scale linearly. The main reasons are: +- **Context switching:** The CPU spends too much time saving and loading thread states instead of running my actual code. +- **Contention & Synchronization overhead:** More threads mean more competition for the same locks. Managing these locks takes time. +- **Cache coherence:** Threads on different CPU cores modify shared data, forcing the CPU to constantly update and synchronize caches across cores, which slows down the memory bus. + +⚠️ Deadlocks + +**6. Deadlocks often only appear in production, not during testing.** +During local testing, my computer usually runs threads fast and with low load, so they often execute sequentially and never hit that exact timing needed for a deadlock. In production, thousands of users hit the system concurrently with unpredictable network delays, creating the perfect random interleaving of threads that causes a deadlock cycle. +**Strategies to expose deadlocks:** +1. **Stress/Load Testing:** I can write a test that spawns hundreds of threads simulating simultaneous high-volume transactions to increase lock contention. +2. **Strategic Thread.sleep():** I can add `Thread.sleep(10)` or `Thread.yield()` right after a thread acquires its first lock but before it gets the second one. This forces a context switch and drastically increases the chance of catching a cyclic deadlock. \ 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..5282225 100644 --- a/src/main/java/dev/banking/model/BankAccount.java +++ b/src/main/java/dev/banking/model/BankAccount.java @@ -1,18 +1,10 @@ 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 +15,56 @@ 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"); + if (amount <= 0) return; + + 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"); + if (amount <= 0) return; + + 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 (this == target || amount <= 0) { + return; + } + + BankAccount firstLock = this.accountId < target.getAccountId() ? this : target; + BankAccount secondLock = this.accountId < target.getAccountId() ? target : this; + + firstLock.lock.lock(); + try { + secondLock.lock.lock(); + try { + this.balance -= amount; + target.balance += amount; + } finally { + secondLock.lock.unlock(); + } + } finally { + firstLock.lock.unlock(); + } } } \ No newline at end of file