Compare commits
3
Commits
fa95f2ebeb
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed4473a239 | ||
|
|
69620f3e55 | ||
|
|
b4af6880fe |
+97
@@ -0,0 +1,97 @@
|
|||||||
|
## Question 1
|
||||||
|
An **atomic variable** is a special type of variable that performs operations
|
||||||
|
|
||||||
|
The purpose of using them is to prevent **race conditions**
|
||||||
|
|
||||||
|
- **Atomic variables**: thread-safe for simple operations (like increment, update).
|
||||||
|
|
||||||
|
- **Ordinary variables**: can cause race conditions if multiple threads change them together without protection.
|
||||||
|
|
||||||
|
## Question 2
|
||||||
|
|
||||||
|
Examples of classes in java.util.concurrent.atomic:
|
||||||
|
|
||||||
|
1. AtomicInteger
|
||||||
|
2. AtomicLong
|
||||||
|
3. AtomicBoolean
|
||||||
|
4. AtomicReference
|
||||||
|
|
||||||
|
AtomicInteger:
|
||||||
|
Used as a thread-safe counter. For example, in a multithreaded server, multiple threads can increase the number of requests safely without using synchronized.
|
||||||
|
|
||||||
|
## Question 3
|
||||||
|
|
||||||
|
Atomic variables: It's better for simple operations on a single value (increment, update, compare-and-set).
|
||||||
|
They are usually faster and lighter because they avoid blocking threads.
|
||||||
|
|
||||||
|
Locks: Used when multiple operations must happen together. Threads wait until the lock is released.
|
||||||
|
|
||||||
|
|
||||||
|
Use a lock when:
|
||||||
|
|
||||||
|
- Multiple variables must stay consistent together
|
||||||
|
|
||||||
|
- A complex sequence of actions must be protected
|
||||||
|
|
||||||
|
- You need critical sections with more control
|
||||||
|
|
||||||
|
|
||||||
|
Use an atomic variable when:
|
||||||
|
|
||||||
|
- Only one variable is shared
|
||||||
|
|
||||||
|
- Operations are simple (counter)
|
||||||
|
|
||||||
|
- High performance and low overhead are important
|
||||||
|
|
||||||
|
|
||||||
|
## Question 4
|
||||||
|
|
||||||
|
A program can be free of race conditions but still be slow under high contention because correctness does not mean good performance.
|
||||||
|
Threads may work safely but spend time waiting instead of doing useful work.
|
||||||
|
|
||||||
|
Three factors that limit scalability:
|
||||||
|
|
||||||
|
1. Lock Contention
|
||||||
|
Many threads try to access the same lock. Only one can continue, so others wait, reducing parallelism.
|
||||||
|
|
||||||
|
|
||||||
|
2. Context Switching
|
||||||
|
The CPU constantly switches between threads. Frequent switching adds overhead and wastes time.
|
||||||
|
|
||||||
|
|
||||||
|
3. Synchronization Overhead
|
||||||
|
Operations like locks, atomic updates, and coordination between threads require extra CPU work and memory synchronization.
|
||||||
|
|
||||||
|
|
||||||
|
## Question 5
|
||||||
|
|
||||||
|
Adding more threads does not always improve performance because after a certain point, threads start spending more time coordinating and competing than doing actual work.
|
||||||
|
|
||||||
|
1. When there are too many threads, the CPU frequently switches between them.
|
||||||
|
Saving and restoring thread states creates overhead and reduces efficiency.
|
||||||
|
|
||||||
|
|
||||||
|
2. Multiple threads may compete for the same resources (locks, memory, shared data). Some threads must wait, so parallel execution decreases.
|
||||||
|
|
||||||
|
|
||||||
|
3. Each CPU core has its own cache. When several threads modify shared data, caches must stay synchronized,
|
||||||
|
creating extra communication and slowing execution.
|
||||||
|
|
||||||
|
|
||||||
|
4. Locks, atomic operations, and coordination mechanisms require additional processing time to maintain correctness.
|
||||||
|
|
||||||
|
|
||||||
|
## Question 6
|
||||||
|
|
||||||
|
Deadlocks often appear in production but not during testing. During testing, threads may run in a favorable order and
|
||||||
|
never reach the lock sequence that causes deadlock. In production, different timing, higher load, and more threads can create the exact conditions needed.
|
||||||
|
|
||||||
|
Two strategies to expose deadlocks during testing:
|
||||||
|
|
||||||
|
1. Stress / Load Testing
|
||||||
|
Run the program with many threads, repeated executions, and high concurrency to increase the chance of problems.
|
||||||
|
|
||||||
|
|
||||||
|
2. Introduce Scheduling Variations
|
||||||
|
Add random delays, sleeps, or use concurrency testing tools to force different execution orders and increase the probability of triggering deadlocks.
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
package dev.banking.model;
|
package dev.banking.model;
|
||||||
|
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
public class BankAccount {
|
public class BankAccount {
|
||||||
|
|
||||||
private final int accountId;
|
private final int accountId;
|
||||||
private long balance;
|
private long balance;
|
||||||
|
private Lock lock = new ReentrantLock();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Students may introduce additional fields
|
* Students may introduce additional fields
|
||||||
@@ -23,44 +27,44 @@ public class BankAccount {
|
|||||||
return accountId;
|
return accountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Return the current balance in a thread-safe way.
|
||||||
* TODO:
|
|
||||||
* Return the current balance in a thread-safe way.
|
|
||||||
*
|
*
|
||||||
* Requirements:
|
* Requirements:
|
||||||
* - Must be safe under concurrent reads/writes
|
* - Must be safe under concurrent reads/writes
|
||||||
* - Should not block unnecessarily if using read/write locks
|
* - Should not block unnecessarily if using read/write locks
|
||||||
*/
|
*/
|
||||||
public long getBalance() {
|
public long getBalance() {
|
||||||
throw new UnsupportedOperationException("TODO: implement thread-safe balance read");
|
|
||||||
|
lock.lock();
|
||||||
|
try{
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Increase balance atomically.
|
||||||
* TODO:
|
|
||||||
* Increase balance atomically.
|
|
||||||
*
|
*
|
||||||
* Requirements:
|
* Requirements:
|
||||||
* - Must not lose updates under concurrency
|
* - Must not lose updates under concurrency
|
||||||
*/
|
*/
|
||||||
public void deposit(long amount) {
|
public synchronized void deposit(long amount) {
|
||||||
throw new UnsupportedOperationException("TODO: implement thread-safe deposit");
|
balance += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Decrease balance atomically.
|
||||||
* TODO:
|
|
||||||
* Decrease balance atomically.
|
|
||||||
*
|
*
|
||||||
* Requirements:
|
* Requirements:
|
||||||
* - Must not cause race conditions
|
* - Must not cause race conditions
|
||||||
* - Negative balance handling is NOT required unless you decide
|
* - Negative balance handling is NOT required unless you decide
|
||||||
* to extend the system (optional)
|
* to extend the system (optional)
|
||||||
*/
|
*/
|
||||||
public void withdraw(long amount) {
|
public synchronized void withdraw(long amount) {
|
||||||
throw new UnsupportedOperationException("TODO: implement thread-safe withdraw");
|
balance -= amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO:
|
|
||||||
* Transfer money between two accounts atomically.
|
* Transfer money between two accounts atomically.
|
||||||
*
|
*
|
||||||
* IMPORTANT REQUIREMENTS:
|
* IMPORTANT REQUIREMENTS:
|
||||||
@@ -73,6 +77,33 @@ public class BankAccount {
|
|||||||
* - Or tryLock with retry strategy
|
* - Or tryLock with retry strategy
|
||||||
*/
|
*/
|
||||||
public void transfer(BankAccount target, long amount) {
|
public void transfer(BankAccount target, long amount) {
|
||||||
throw new UnsupportedOperationException("TODO: implement atomic deadlock-free transfer");
|
|
||||||
|
BankAccount first, second;
|
||||||
|
|
||||||
|
if(target == this) return;
|
||||||
|
|
||||||
|
if (this.getAccountId() < target.getAccountId()) {
|
||||||
|
first = this;
|
||||||
|
second = target;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
first = target;
|
||||||
|
second = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
first.lock.lock();
|
||||||
|
try {
|
||||||
|
second.lock.lock();
|
||||||
|
try {
|
||||||
|
this.withdraw(amount);
|
||||||
|
target.deposit(amount);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
second.lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
first.lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user