From 783359667aa0e1638d0d4fdef7e962f783bf29c2 Mon Sep 17 00:00:00 2001 From: Arshida_0 Date: Mon, 15 Jun 2026 01:27:43 +0430 Subject: [PATCH] HW 09 --- .idea/.gitignore | 10 ++ .idea/compiler.xml | 13 ++ .idea/encodings.xml | 7 + .idea/jarRepositories.xml | 20 +++ .idea/misc.xml | 12 ++ .idea/vcs.xml | 6 + Answers.md | 166 ++++++++++++++++++ pom.xml | 22 ++- .../java/dev/banking/model/BankAccount.java | 27 ++- 9 files changed, 274 insertions(+), 9 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 Answers.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/Answers.md b/Answers.md new file mode 100644 index 0000000..1b918aa --- /dev/null +++ b/Answers.md @@ -0,0 +1,166 @@ +## ⚛️ Atomic Variables & Synchronization + +--- + + +### **1 -** Atomic variables solve thread-safety problems without using explicit synchronization (synchronized blocks or Lock objects). Their primary purposes are: + +1. Provide thread-safe operations on single variables without locks + +2. Enable non-blocking algorithms with better performance under moderate contention + +3. Ensure visibility across threads (like volatile variables) + +4. Support atomic read-modify-write operations (e.g., increment, compare-and-set) + + +### **2 -** Four Atomic Classes from java.util.concurrent.atomic: + +1. **AtomicInteger:** Atomic operations for int values + +2. **AtomicLong:** Atomic operations for long values + +3. **AtomicBoolean:** Atomic operations for boolean values + +4. **AtomicReference**: Atomic operations for object references + +- A use case is when a web server needs to generate unique, sequential request IDs across thousands of concurrent threads. + + +### **3 -** When to use… + +- **Atomic Variables:** when you're updating only one variable with simple operations under moderate contention. + +- **Locks:** when you need to coordinate multiple resources, have complex conditions, or require fairness or blocking semantics. + +| Aspect | Locks (synchronized, ReentrantLock) | Atomic Variables | +|----------------------|--------------------------------------------|-------------------------| +| Mechanism | Blocking (threads wait/park) | Non-blocking (CAS operations) | +| Scope Can | protect multiple variables/operations | Single variable only | +| Overhead | Higher (context switching, OS involvement) | Lower (CPU-level instructions) | +| Contention handling | Threads block and may be descheduled | Threads retry without blocking | +| Deadlock risk | Yes (especially with multiple locks) | No | +| Fairness options | Available (e.g., ReentrantLock(true)) | No (CAS is inherently unfair) | +| Composite operations | Easy (multiple steps together) | Difficult or impossible | + + +### **- Bonus:** + +```java +import java.util.concurrent.atomic.AtomicInteger; + +public class example { + private static int count1; + private static AtomicInteger count2 = new AtomicInteger(0); + + public example() {} + + public static void increment() { count1++; } + + public static void atomicIncrement() { count2.incrementAndGet(); } + + public static void main(String args[]) throws InterruptedException { + + Runnable r = () -> { + for (int i = 1; i <= 1000; i++) { + atomicIncrement(); + increment(); + } + }; + + Thread t1 = new Thread(r, "thread-1"); + Thread t2 = new Thread(r, "thread-2"); + Thread t3 = new Thread(r, "thread-3"); + + t1.start(); + t2.start(); + t3.start(); + + t1.join(); + t2.join(); + t3.join(); + + System.out.println("-int- variable value: " + count1 + " -AtomicInteger- variable value: " + count2); + } +} +``` + +Output: +```text +-int- variable value: 2971 -AtomicInteger- variable value: 3000 +``` + + +## 🔒 Locks & Concurrent Design + +--- + + +### **4 -** A program can be free of race conditions through proper synchronization (locks, atomic variables, concurrent collections), but still suffer from: + +- **Contention:** Threads competing for the same resources + +- **Over-synchronization:** Too much or too coarse-grained locking + +- **Hardware limitations:** Cache coherence traffic, false sharing + +Concurrency-related factors that may limit scalability even when correctness is guaranteed: + +1. **Lock Contention (Serialization):** + Even with correct locking, if threads frequently wait for locks, execution becomes effectively serialized. Threads queue up despite having multiple CPU cores. + +2. **Cache Coherence Traffic (The "Hidden" Contention):** + Even lock-free atomic variables generate significant CPU cache traffic that limits scalability. + +3. **False Sharing:** + When threads modify different variables that accidentally share the same CPU cache line, the cache coherence protocol treats them as if they were the same variable. + + +### **5 -** This is the scalability ceiling problem. Adding threads eventually hurts performance due to coordination overhead. + +1. **Context Switching Overhead:** + When more threads than CPU cores exist, the OS constantly switches between threads, saving/restoring state. + +2. **Contention for Shared Resources:** + As threads increase, probability of conflict superlinearly increases. + +3. **Cache Coherence Traffic:** + Modern CPUs maintain cache coherence (MESI protocol). When multiple cores modify shared data, they generate coherence traffic that doesn't exist with fewer threads. + +4. **Synchronization Overhead (Locking):** + Even without contention, acquiring/releasing locks has intrinsic overhead. + + +## ⚠️ Deadlocks + +--- + + +### **6 -** A deadlock requires four conditions: + +- **Mutual exclusion:** Resources can't be shared + +- **Hold and wait:** Thread holds one resource while waiting for another + +- **No preemption:** Resources can't be forcibly taken + +- **Circular wait:** Threads form a cycle of dependencies + +But even with all conditions present, a deadlock only occurs when threads acquire locks in precisely the wrong order at precisely the wrong time. +Specific scheduling factors that hide deadlocks: + +1. **Low contention in tests:** Threads rarely overlap in lock acquisition + +2. **Fast operations:** Critical sections so brief that interleaving is improbable + +3. **Small thread pools:** Fewer permutations of lock ordering + +4. **Deterministic scheduling:** Same interleaving every run (lulls developers into false safety) + +5. **No GC pressure:** GC can pause threads at vulnerable moments + +*Strategy 1 :* Manual Lock Order Inversion (Eclipse Contest) +Force the circular wait condition by deliberately inverting lock order in tests. + +*Strategy 2 :* Inject Preemptive Scheduling Points (ThreadWeaver) +Force thread context switches at vulnerable points using controlled test frameworks like ThreadWeaver or JCStress. \ No newline at end of file diff --git a/pom.xml b/pom.xml index 33ea6f3..4d957c9 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,25 @@ org.junit.jupiter junit-jupiter - 5.12.2 + 5.11.4 + test + + + junit + junit + RELEASE + test + + + junit + junit + RELEASE + test + + + junit + junit + RELEASE test @@ -28,7 +46,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.5.3 + 3.5.2 diff --git a/src/main/java/dev/banking/model/BankAccount.java b/src/main/java/dev/banking/model/BankAccount.java index 745ede2..b66bbac 100644 --- a/src/main/java/dev/banking/model/BankAccount.java +++ b/src/main/java/dev/banking/model/BankAccount.java @@ -1,9 +1,14 @@ package dev.banking.model; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantLock; + public class BankAccount { private final int accountId; private long balance; + private ReentrantLock lock = new ReentrantLock(); /* * Students may introduce additional fields @@ -31,8 +36,8 @@ public class BankAccount { * - 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"); + public synchronized long getBalance() { //??????????????????????????/? + return balance; } /* @@ -42,8 +47,8 @@ public class BankAccount { * 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; } /* @@ -55,8 +60,8 @@ public class BankAccount { * - 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; } /* @@ -73,6 +78,14 @@ 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 = target.getAccountId() < accountId ? target : this ; + BankAccount second = target.getAccountId() < accountId ? this : target ; + + synchronized (first) { + synchronized (second) { + target.deposit(amount); + this.withdraw(amount); + } + } } } \ No newline at end of file -- 2.54.0