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..a9076af
--- /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/Answers.md b/Answers.md
new file mode 100644
index 0000000..2c5a244
--- /dev/null
+++ b/Answers.md
@@ -0,0 +1,48 @@
+# Java Concurrency: Atomic Variables & Locks
+
+### 1. Atomic Variables
+Atomic variables are tools that let us update a value safely when many threads are running. They ensure that an action (like adding 1) happens **all at once** without being interrupted.
+
+* **Difference:** Normal variables can lose data if two threads change them at the exact same time. Atomic variables use a "try-and-retry" method (CAS) to stay accurate without stopping other threads.
+
+### 2. Common Atomic Classes
+* `AtomicInteger`
+* `AtomicLong`
+* `AtomicBoolean`
+* `AtomicReference`
+
+**Use Case:** We use `AtomicInteger` for a **hit counter** on a website. It keeps the total count correct even if thousands of users click a button at the same second.
+
+### 3. Locks vs. Atomic Variables
+
+| Feature | Atomic Variables | Locks (`synchronized`) |
+| :--- | :--- | :--- |
+| **Speed** | Very Fast | Slower |
+| **Thread Behavior** | Keep running (no waiting) | Stop and wait their turn |
+| **Best For** | Single numbers or flags | Groups of variables or big tasks |
+
+* **We use Atomic Variables when:** We only need to change one value quickly and want to avoid the slowdown of locking.
+* **We use Locks when:** We need to update **multiple related values** together or when the work takes a long time (like saving a file).
+
+### 4. Poor Performance without Race Conditions
+Even if our code is "correct" (no data is lost), it can still be slow if many threads fight for the same resources. This is called **high contention**.
+
+**Factors that limit scaling:**
+1. **Lock Contention:** Many threads wait in a long line for one lock, so only one thread actually works at a time.
+2. **Context Switching:** The CPU spends more time "swapping" threads in and out than actually running our code.
+3. **Memory Bottlenecks:** Threads might be waiting for data to move between the main memory and the CPU.
+
+### 5. Why More Threads Can Slow Us Down
+Adding more threads has a "cost" that eventually outweighs the benefits.
+
+- **Context Switching:** Every time the CPU moves from one thread to another, it has to save and load data. This wastes time.
+- **Contention:** If we have 100 threads but only 1 resource, 99 threads are sitting idle, which wastes memory.
+- **Cache Coherence:** When one thread changes data, the CPU must tell all other cores to update their private "caches." This constant communication slows down the whole system.
+- **Synchronization Overhead:** The tools we use to stay safe (like locks or atomic signals) require extra CPU work to manage.
+
+### 6. Deadlocks in Production vs. Testing
+Deadlocks depend on **timing**. In testing, threads might always run in a "safe" order because the computer is less busy. In production, unexpected delays or high traffic can cause threads to grab locks in the "wrong" order, causing a freeze.
+
+**Strategies to find deadlocks during testing:**
+1. **Thread Fuzzing:** We can add random, tiny delays (like `Thread.sleep()`) in our code during testing. This forces different timings and helps expose hidden deadlocks.
+2. **Stress Testing:** We can run the program with a much higher number of threads and data than we expect. This makes it more likely that the rare "wrong timing" will happen.
\ 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..65b5f23 100644
--- a/src/main/java/dev/banking/model/BankAccount.java
+++ b/src/main/java/dev/banking/model/BankAccount.java
@@ -1,18 +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;
-
- /*
- * Students may introduce additional fields
- * such as:
- * - Lock / ReentrantLock
- * - ReadWriteLock
- * - Object monitor
- * - etc.
- */
+ private final Lock lock = new ReentrantLock();
public BankAccount(int accountId, long initialBalance) {
this.accountId = accountId;
@@ -23,56 +18,48 @@ 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");
+ 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");
+ 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");
+ BankAccount first = this.accountId < target.accountId ? this : target;
+ BankAccount second = this.accountId < target.accountId ? target : 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
diff --git a/src/main/java/dev/banking/model/DepositTransaction.java b/src/main/java/dev/banking/model/DepositTransaction.java
index f4798d2..19869ee 100644
--- a/src/main/java/dev/banking/model/DepositTransaction.java
+++ b/src/main/java/dev/banking/model/DepositTransaction.java
@@ -1,8 +1,5 @@
package dev.banking.model;
-/**
- * Represents a deposit operation.
- */
public final class DepositTransaction extends Transaction {
private final int accountId;
diff --git a/src/main/java/dev/banking/model/Transaction.java b/src/main/java/dev/banking/model/Transaction.java
index 5d53921..73b3f88 100644
--- a/src/main/java/dev/banking/model/Transaction.java
+++ b/src/main/java/dev/banking/model/Transaction.java
@@ -1,8 +1,5 @@
package dev.banking.model;
-/**
- * Base class for all transaction types.
- */
public abstract class Transaction {
private final int amount;
diff --git a/src/main/java/dev/banking/model/TransferTransaction.java b/src/main/java/dev/banking/model/TransferTransaction.java
index 89d3a57..77eef48 100644
--- a/src/main/java/dev/banking/model/TransferTransaction.java
+++ b/src/main/java/dev/banking/model/TransferTransaction.java
@@ -1,8 +1,5 @@
package dev.banking.model;
-/**
- * Represents a transfer operation between two accounts.
- */
public final class TransferTransaction
extends Transaction {
diff --git a/src/main/java/dev/banking/model/WithdrawTransaction.java b/src/main/java/dev/banking/model/WithdrawTransaction.java
index ba1ebd2..417f503 100644
--- a/src/main/java/dev/banking/model/WithdrawTransaction.java
+++ b/src/main/java/dev/banking/model/WithdrawTransaction.java
@@ -1,8 +1,5 @@
package dev.banking.model;
-/**
- * Represents a withdrawal operation.
- */
public final class WithdrawTransaction extends Transaction {
private final int accountId;
diff --git a/src/main/java/dev/banking/monitor/LiveMonitor.java b/src/main/java/dev/banking/monitor/LiveMonitor.java
index a625199..caed995 100644
--- a/src/main/java/dev/banking/monitor/LiveMonitor.java
+++ b/src/main/java/dev/banking/monitor/LiveMonitor.java
@@ -1,7 +1,6 @@
package dev.banking.monitor;
import dev.banking.model.BankAccount;
-
import java.util.Collection;
public class LiveMonitor {
@@ -9,15 +8,12 @@ public class LiveMonitor {
public void update(
Collection accounts
) {
-
for (BankAccount account : accounts) {
-
System.out.printf(
"Account %d -> %d%n",
account.getAccountId(),
account.getBalance()
);
-
}
}
}
\ No newline at end of file
diff --git a/src/main/java/dev/banking/processor/TransactionProcessor.java b/src/main/java/dev/banking/processor/TransactionProcessor.java
index 58d7e36..9e934d5 100644
--- a/src/main/java/dev/banking/processor/TransactionProcessor.java
+++ b/src/main/java/dev/banking/processor/TransactionProcessor.java
@@ -1,7 +1,6 @@
package dev.banking.processor;
import dev.banking.model.*;
-
import java.util.Map;
public class TransactionProcessor {
@@ -15,33 +14,19 @@ public class TransactionProcessor {
}
public void process(Transaction tx) {
-
if (tx instanceof DepositTransaction deposit) {
-
BankAccount account = accounts.get(deposit.getAccountId());
-
account.deposit(deposit.getAmount());
}
-
else if (tx instanceof WithdrawTransaction withdraw) {
-
BankAccount account = accounts.get(withdraw.getAccountId());
-
account.withdraw(withdraw.getAmount());
}
-
else if (tx instanceof TransferTransaction transfer) {
-
BankAccount source = accounts.get(transfer.getSourceAccountId());
-
BankAccount target = accounts.get(transfer.getTargetAccountId());
-
- source.transfer(
- target,
- transfer.getAmount()
- );
+ source.transfer(target, transfer.getAmount());
}
-
else {
throw new IllegalArgumentException(
"Unknown transaction type: " + tx.getClass()
diff --git a/src/main/java/dev/banking/service/BankingSystem.java b/src/main/java/dev/banking/service/BankingSystem.java
index 255e01c..2b09b0d 100644
--- a/src/main/java/dev/banking/service/BankingSystem.java
+++ b/src/main/java/dev/banking/service/BankingSystem.java
@@ -2,22 +2,9 @@ package dev.banking.service;
import dev.banking.model.*;
import dev.banking.processor.TransactionProcessor;
-
import java.util.List;
import java.util.concurrent.ExecutorService;
-/**
- * Dispatches a list of transactions to a shared ExecutorService
- * for concurrent (asynchronous) processing.
- *
- * Each transaction is submitted as an independent task and may
- * be executed in parallel depending on thread availability.
- *
- * No ordering guarantees are provided between transactions.
- *
- * Lifecycle management of the ExecutorService (creation,
- * shutdown, termination) is handled outside this class.
- */
public class BankingSystem {
private final ExecutorService executor;
@@ -34,13 +21,10 @@ public class BankingSystem {
public void processTransactions(
List transactions
) {
-
for (Transaction tx : transactions) {
-
executor.submit(() -> {
processor.process(tx);
});
-
}
}
}
\ No newline at end of file