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