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/Answer.md b/Answer.md
new file mode 100644
index 0000000..2332841
--- /dev/null
+++ b/Answer.md
@@ -0,0 +1,73 @@
+## Question 1
+
+
+1 - What are atomic variables?
+
+Atomic variables are variables that provide thread-safe operations without using explicit locks. Operations such as incrementing or updating a value are performed atomically, meaning they cannot be interrupted by other threads.
+
+Ordinary variables do not provide this guarantee. For example, the expression `counter++` consists of multiple steps, and different threads may interfere with each other, causing race conditions.
+
+Atomic variables are mainly used to safely share data between multiple threads.
+
+## Question 2
+
+2 - Name at least four classes from the java.util.concurrent.atomic package that provide atomic operations for different data types.
+
+Some classes from the `java.util.concurrent.atomic` package are:
+
+- AtomicInteger
+- AtomicLong
+- AtomicBoolean
+- AtomicReference
+
+A common use case for `AtomicInteger` is a shared counter. Multiple threads can safely increment the counter without using locks.
+
+## Question 3
+
+3 - Compare locks with atomic variables.
+
+Atomic variables are usually faster and simpler for operations on a single variable. They have lower overhead and do not require explicit locking.
+
+Locks are better when multiple operations or multiple shared variables must be protected together. They provide more flexibility but usually have higher overhead.
+
+Use atomic variables for simple updates such as counters. Use locks for complex critical sections that involve several operations.
+
+## Question 4
+
+4 - A program is completely free of race conditions but still performs poorly under high contention.
+
+A program can be free of race conditions and still perform poorly because correctness does not guarantee scalability.
+
+Some factors that limit performance are:
+
+1. Lock contention, where many threads wait for the same lock.
+2. Thread blocking, which reduces parallel execution.
+3. Synchronization overhead, which adds extra work for coordinating threads.
+
+As a result, the program remains correct but may not scale well under heavy load.
+
+## Question 5
+
+5 - Many concurrent systems experience performance degradation as the number of threads increases.
+
+Adding more threads does not always improve performance.
+
+- Context switching takes CPU time when the operating system switches between threads.
+- Contention happens when many threads compete for the same resources.
+- Cache coherence creates extra work for processors to keep shared data consistent.
+- Synchronization overhead increases because locks and coordination mechanisms require additional processing.
+
+Because of these costs, too many threads can actually reduce performance.
+
+## Question 6
+
+6 - Deadlocks often only appear in production, not during testing.
+
+Deadlocks often depend on specific thread schedules. During testing, the required scheduling order may never occur. In production, higher load and different timing make deadlocks more likely.
+
+Two ways to expose deadlocks during testing are:
+
+1. Stress testing with many threads and repeated executions.
+2. Adding random delays to create different thread interleavings.
+
+These techniques increase the chance of reproducing deadlock situations before deployment.
\ 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..f8a4b72 100644
--- a/src/main/java/dev/banking/model/BankAccount.java
+++ b/src/main/java/dev/banking/model/BankAccount.java
@@ -1,18 +1,12 @@
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 +17,61 @@ 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;
+ BankAccount second;
+
+ if (this.accountId < target.accountId) {
+ first = this;
+ second = target;
+ } else {
+ first = target;
+ second = this;
+ }
+
+ first.lock.lock();
+ second.lock.lock();
+
+ try {
+ this.balance -= amount;
+ target.balance += amount;
+ } finally {
+ second.lock.unlock();
+ first.lock.unlock();
+ }
}
}
\ No newline at end of file