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..8306744
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Answers.md b/Answers.md
new file mode 100644
index 0000000..9cdba0f
--- /dev/null
+++ b/Answers.md
@@ -0,0 +1,229 @@
+# Ninth Assignment — Answers
+
+---
+
+### ⚛️ Atomic Variables & Synchronization
+
+---
+
+### **1 - What are atomic variables?**
+
+Atomic variables are variables that support **lock-free, thread-safe operations**. This means operations on them (such as increment, compare-and-set, etc.) are performed as a single indivisible step.
+
+Their main purpose is to **prevent race conditions** when multiple threads access and modify shared data concurrently.
+
+#### Difference from ordinary variables:
+
+* **Ordinary variables (non-atomic):**
+
+ * Operations like `x++` are NOT atomic.
+ * They consist of multiple steps: read → modify → write.
+ * This can lead to race conditions.
+
+* **Atomic variables:**
+
+ * Provide built-in thread-safe operations.
+ * Use low-level CPU instructions (like CAS – Compare-And-Swap).
+ * No need for explicit synchronization (like `synchronized` or locks).
+
+---
+
+### **2 - Atomic classes in `java.util.concurrent.atomic`**
+
+Examples of atomic classes:
+
+* `AtomicInteger`
+* `AtomicLong`
+* `AtomicBoolean`
+* `AtomicReference`
+
+#### Example use case: `AtomicInteger`
+
+`AtomicInteger` is commonly used as a **thread-safe counter**.
+
+Example:
+
+* Counting number of requests in a web server
+* Tracking successful operations across multiple threads
+
+It avoids race conditions without using locks, improving performance under moderate contention.
+
+---
+
+### **3 - Locks vs Atomic Variables**
+
+#### Atomic Variables:
+
+**Advantages:**
+
+* Faster (lock-free)
+* No blocking
+* Simple for single-variable operations
+
+**Limitations:**
+
+* Only suitable for **simple operations**
+* Not useful for multi-step or multi-variable logic
+
+---
+
+#### Locks (`synchronized`, `ReentrantLock`):
+
+**Advantages:**
+
+* Can protect **complex operations**
+* Allow coordination across multiple variables
+* Support conditions and waiting
+
+**Disadvantages:**
+
+* Slower due to blocking
+* Can cause deadlocks if misused
+
+---
+
+#### When to use which?
+
+* Use **Atomic Variables** when:
+
+ * You have simple operations (e.g., increment counter)
+ * No need for coordination between multiple variables
+
+* Use **Locks** when:
+
+ * Multiple shared variables are involved
+ * You need atomic multi-step operations
+ * You need waiting/notification mechanisms
+
+---
+
+### 🎯 Bonus Task — Example Program
+
+```java
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class AtomicDemo {
+ static int normalCounter = 0;
+ static AtomicInteger atomicCounter = new AtomicInteger(0);
+
+ public static void main(String[] args) throws InterruptedException {
+ int threads = 10;
+ Thread[] workers = new Thread[threads];
+
+ for (int i = 0; i < threads; i++) {
+ workers[i] = new Thread(() -> {
+ for (int j = 0; j < 1000; j++) {
+ normalCounter++; // NOT thread-safe
+ atomicCounter.incrementAndGet(); // thread-safe
+ }
+ });
+ workers[i].start();
+ }
+
+ for (Thread t : workers) {
+ t.join();
+ }
+
+ System.out.println("Normal Counter: " + normalCounter);
+ System.out.println("Atomic Counter: " + atomicCounter.get());
+ }
+}
+```
+
+Expected result:
+
+* `atomicCounter` will always be correct (10000)
+* `normalCounter` may be less due to race conditions
+
+---
+
+### 🔒 Locks & Concurrent Design
+
+---
+
+### **4 - Race-free but poor performance**
+
+A program can be completely correct (no race conditions) but still perform poorly due to **high contention and synchronization overhead**.
+
+#### Reasons:
+
+1. **High contention**
+
+ * Many threads compete for the same lock
+ * Threads spend time waiting instead of doing work
+
+2. **Excessive synchronization**
+
+ * Overuse of locks reduces parallelism
+ * Even independent operations get blocked
+
+3. **Lock granularity issues**
+
+ * Coarse-grained locks (one big lock)
+ * Prevent multiple threads from working in parallel
+
+---
+
+### **5 - Why more threads ≠ better performance**
+
+Adding more threads can hurt performance due to:
+
+#### 1. Context Switching
+
+* CPU switches between threads
+* This has overhead and wastes time
+
+#### 2. Contention
+
+* Threads compete for shared resources (locks, memory)
+* More threads → more waiting
+
+#### 3. Cache Coherence
+
+* CPUs maintain consistency of cached data
+* Frequent updates cause cache invalidation
+* Slows down execution
+
+#### 4. Synchronization Overhead
+
+* Locks and coordination add extra cost
+* More threads → more synchronization
+
+---
+
+### ⚠️ Deadlocks
+
+---
+
+### **6 - Why deadlocks appear in production**
+
+Deadlocks depend on **thread scheduling**, which is:
+
+* Non-deterministic
+* Timing-dependent
+
+In testing:
+
+* Fewer threads
+* Predictable execution
+
+In production:
+
+* High concurrency
+* Different timing → circular waits may occur
+
+---
+
+#### Strategies to expose deadlocks:
+
+1. **Stress testing**
+
+ * Run with many threads
+ * Increase contention
+ * Repeat tests multiple times
+
+2. **Introduce artificial delays**
+
+ * Add `sleep()` between lock acquisitions
+ * Makes timing issues more visible
+ * Increases probability of 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..c2a85c2 100644
--- a/src/main/java/dev/banking/model/BankAccount.java
+++ b/src/main/java/dev/banking/model/BankAccount.java
@@ -1,78 +1,87 @@
package dev.banking.model;
-public class BankAccount {
+import java.util.concurrent.locks.Condition;
+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();
+ private final Condition sufficientFunds = lock.newCondition();
- public BankAccount(int accountId, long initialBalance) {
+ public BankAccount(int accountId, long initialBalance)
+ {
this.accountId = accountId;
this.balance = initialBalance;
}
- public int getAccountId() {
- return accountId;
+ public int getAccountId() {return accountId;}
+
+ public long getBalance()
+ {
+ lock.lock();
+ try {return balance;}
+ finally {lock.unlock();}
}
- /*
- * 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");
+ public void deposit(long amount)
+ {
+ lock.lock();
+ try
+ {
+ balance += amount;
+ sufficientFunds.signalAll(); // wake waiting threads
+ }
+ 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");
+ public void withdraw(long amount)
+ {
+ lock.lock();
+ try
+ {
+ while (balance < amount) {sufficientFunds.await();}
+ balance -= amount;
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ 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");
- }
+ public void transfer(BankAccount target, long amount)
+ {
+ if (this == target) return;
- /*
- * 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 = this.accountId < target.accountId ? this : target;
+ BankAccount second = this.accountId < target.accountId ? target : this;
+
+ first.lock.lock();
+ second.lock.lock();
+
+ try
+ {
+ while (this.balance < amount) {this.sufficientFunds.await();}
+
+ this.balance -= amount;
+ target.balance += amount;
+
+ this.sufficientFunds.signalAll();
+ target.sufficientFunds.signalAll();
+
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ finally
+ {
+ second.lock.unlock();
+ first.lock.unlock();
+ }
}
}
\ No newline at end of file