Complete Assignment #1

Merged
peyman merged 2 commits from develop into main 2026-07-18 17:10:08 +00:00
8 changed files with 168 additions and 4 deletions
+10
View File
@@ -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/
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="HW-09-Advanced-Multithreading" />
</profile>
</annotationProcessing>
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://maven.myket.ir/" />
</remote-repository>
</component>
</project>
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="25" project-jdk-type="JavaSDK" />
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+47
View File
@@ -0,0 +1,47 @@
## Question 1
An atomic variable in Computer Science refers to a basic data or input variable that is used to build performance variables. These variables are not summaries or ratios, but rather fundamental building blocks in operational systems.
Atomic variables allow multiple threads to safely read and update a shared value without using explicit locks, guaranteeing that operations like increment-and-update happen as a single, uninterruptible step. Ordinary variables don't provide this guarantee—if multiple threads modify them concurrently, updates can be lost due to race conditions.
## Question 2
`AtomicInteger`
`AtomicLong`
`AtomicBoolean`
`AtomicReference<T>` for any type of object.
## Question 3
| | Locks (`synchronized`/`ReentrantLock`) | Atomic Variables |
|---|---|---|
| Mechanism | Blocking (mutual exclusion) | Lock-free |
| Scope | Can protect multiple statements/variables | Single variable only |
| Performance | Slower under contention | Generally faster |
| Deadlock risk | Possible | None |
| Best for | Complex critical sections | Simple counters, flags, single values |
## Question 4
A program can be completely free of race conditions yet still perform poorly, because the very mechanisms used to guarantee correctness — such as locks or CAS — introduce overhead. When many threads compete for the same shared resource, they end up **blocking or repeatedly retrying**, which sharply reduces throughput even though correctness is fully preserved.
Some concurrency-related factors that may limit scalability even when correctness iss guaranteed:
1. Lock contention
2. Context switching overhead
3. Cache coherence traffic
## Question 5
Despite the three factors given in the previous question there is a vital factor which is **limited CPU cores**.
once threads exceed available cores, they compete for the same processing units, adding scheduling overhead instead of true parallelism.
Context-switching overhead the OS spends more time switching between threads than executing actual work.
Cache coherence traffic shared/false-shared memory locations cause costly cross-core cache invalidation.
## Question 6
A precise timing where two or more threads each acquire one lock and then attempt to acquire the other's lock simultaneously.
1. Stress testing with high concurrency run many more threads than in normal testing.
2. Deliberate interleaving control / thread scheduling tools use tools or techniques that artificially manipulate thread timing to force specific interleavings, such as:
Inserting `Thread.sleep()` or `yield()` calls strategically between lock acquisitions.
@@ -1,10 +1,16 @@
package dev.banking.model;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class BankAccount {
private final int accountId;
private long balance;
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
/*
* Students may introduce additional fields
* such as:
@@ -32,7 +38,12 @@ public class BankAccount {
* - Should not block unnecessarily if using read/write locks
*/
public long getBalance() {
throw new UnsupportedOperationException("TODO: implement thread-safe balance read");
lock.readLock().lock();
try {
return balance;
} finally {
lock.readLock().unlock();
}
}
/*
@@ -43,7 +54,15 @@ public class BankAccount {
* - Must not lose updates under concurrency
*/
public void deposit(long amount) {
throw new UnsupportedOperationException("TODO: implement thread-safe deposit");
if(amount < 0)
throw new IllegalArgumentException("Amount can't be negative!");
lock.writeLock().lock();
try {
balance += amount;
} finally {
lock.writeLock().unlock();
}
}
/*
@@ -56,7 +75,15 @@ public class BankAccount {
* to extend the system (optional)
*/
public void withdraw(long amount) {
throw new UnsupportedOperationException("TODO: implement thread-safe withdraw");
if(amount < 0)
throw new IllegalArgumentException("Amount can't be negative!");
lock.writeLock().lock();
try {
balance -= amount;
} finally {
lock.writeLock().unlock();
}
}
/*
@@ -73,6 +100,28 @@ public class BankAccount {
* - Or tryLock with retry strategy
*/
public void transfer(BankAccount target, long amount) {
throw new UnsupportedOperationException("TODO: implement atomic deadlock-free transfer");
if (amount < 0) {
throw new IllegalArgumentException("Transfer amount cannot be negative");
}
if (this == target) {
throw new IllegalArgumentException("Cannot transfer to the same account");
}
// we order them by their id so that we always lock the first one to prevent deadLocks taking place.
BankAccount first = this.accountId < target.accountId ? this : target;
BankAccount second = this.accountId < target.accountId ? target : first;
first.lock.writeLock().lock();
try {
second.lock.writeLock().lock();
try {
this.balance -= amount;
target.balance += amount;
} finally {
second.lock.writeLock().unlock();
}
} finally {
first.lock.writeLock().unlock();
}
}
}