Compare commits
2
Commits
fa95f2ebeb
...
3cbfa5d187
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cbfa5d187 | ||
|
|
fcac98cab7 |
Generated
+10
@@ -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/
|
||||
Generated
+13
@@ -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>
|
||||
Generated
+7
@@ -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>
|
||||
Generated
+20
@@ -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="Central Repository" />
|
||||
<option name="url" value="https://maven.devneeds.ir/" />
|
||||
</remote-repository>
|
||||
<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>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+12
@@ -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
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,65 @@
|
||||
# Theoretical Questions
|
||||
|
||||
|
||||
|
||||
### Q1-What are atomic variables?
|
||||
|
||||
---
|
||||
|
||||
An atomic variable is a type of variable designed so that its update operations are indivisible and free of interference. This means that when an atomic variable is being updated, no other thread can change its value during the operation. However, in non-atomic variables, each operation can be divided; for example, the ++ operation is divided into three operations (reading, adding, and writing).
|
||||
Also, for atomic variables, to change the value of the variables, you must use the methods within the class of that variable.
|
||||
|
||||
|
||||
|
||||
### Q2 - Four classes from the `java.util.concurrent.atomic`
|
||||
|
||||
---
|
||||
|
||||
1. AtomicInteger
|
||||
2. AtomicLong
|
||||
3. AtomicBoolean
|
||||
4. AtomicReference
|
||||
|
||||
For example, AtomicInteger is used for working with integers, which is equivalent to the int variable in a non-atomic way.
|
||||
and we can use some method to update it . for example `get()` , `set()` , `addAndGet()` , `intValue()` , ...
|
||||
|
||||
---
|
||||
|
||||
### Q3-Compare locks with atomic variables.
|
||||
|
||||
Atomic variables exist only for a specific type of data and Atomic variables only support simple operations, and for more complex operations, locks must be used.
|
||||
For applications that do not require high concurrency, using a lock may be sufficient. However, in applications that require high performance and concurrency, atomic variables can be very useful.Using locks may encounter errors, for example when we forget to unlock a lock.
|
||||
|
||||
---
|
||||
|
||||
### Q4-High Contention
|
||||
|
||||
This situation indicates that your program has no correctness issues, but it faces structural bottlenecks in terms of throughput or scalability. Next, we will examine the three main factors that cause this problem in Java applications:
|
||||
1. For example, you might have 100 threads, and due to the presence of a lock, at any moment at most 1 thread performs its work while the other 99 threads remain in the queue, which causes a slow queue.
|
||||
2. Processors bring data from main memory to their cache in units called Cache Line (usually 64 bytes). If two different variables that are constantly modified by two different threads (on separate cores) reside in the same Cache Line, the hardware thinks the data is shared and constantly synchronizes the cores' caches with each other.
|
||||
Problem in Java: Threads effectively wait for each other to update the cache, without actually accessing a shared resource.
|
||||
3. In Java, GC is used to clear objects that are no longer used. For GC to be able to do its job correctly and to ensure that it does not mistakenly delete any live object, in many cases it needs to temporarily stop the entire program or a large part of it. This stoppage is called Stop-the-World (STW). ...
|
||||
|
||||
---
|
||||
|
||||
### Q5-Number of thread
|
||||
|
||||
1. When the CPU switches between threads or processes, it must save the current state (register values, program counter, stack, etc.) and load the next thread's state. This process slows down as the number of threads increases.
|
||||
2. When multiple threads or processes want to access a shared resource simultaneously, they must wait for the other to finish its work. This waiting and locking cause slowdowns.
|
||||
3. In multi-core CPUs, each core has its own cache. If a thread modifies a variable on core A, the copy of that variable in the caches of other cores must also be updated so that all copies are consistent. This cache coherence process (Cache Coherence Protocol) causes delays.
|
||||
4. When we use locks to prevent the competition mechanism, it itself causes a waste of time.
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Q6-Deadlocks
|
||||
|
||||
In test we have a few thread and it is so simple but when we are in production we have most thread and a lot of Calculations
|
||||
we have 2 solution
|
||||
1. we can use more thread when we test our program to br similar to final status.
|
||||
2. when we test our program we can use `sleep()` to change scheduling of threads.
|
||||
|
||||
|
||||
---
|
||||
|
||||
# Finish
|
||||
@@ -1,10 +1,18 @@
|
||||
package dev.banking.model;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class BankAccount {
|
||||
|
||||
|
||||
|
||||
private final int accountId;
|
||||
private long balance;
|
||||
|
||||
private Lock accountLock = new ReentrantLock();
|
||||
private Condition accountCon = accountLock.newCondition();
|
||||
/*
|
||||
* Students may introduce additional fields
|
||||
* such as:
|
||||
@@ -23,56 +31,78 @@ 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");
|
||||
accountLock.lock();
|
||||
try{
|
||||
return this.balance;
|
||||
}finally {
|
||||
accountLock.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");
|
||||
accountLock.lock();
|
||||
try{
|
||||
balance += amount;
|
||||
accountCon.signalAll();
|
||||
}finally {
|
||||
accountLock.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");
|
||||
accountLock.lock();
|
||||
try{
|
||||
while (balance < amount){
|
||||
accountCon.await();
|
||||
}
|
||||
balance -= amount;
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
accountLock.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");
|
||||
|
||||
if(this.getAccountId() == target.getAccountId()){
|
||||
return;
|
||||
}
|
||||
|
||||
BankAccount first = this.getAccountId() < target.getAccountId() ? this : target;
|
||||
BankAccount second = this.getAccountId() < target.getAccountId() ? target : this;
|
||||
|
||||
|
||||
first.accountLock.lock();
|
||||
|
||||
try {
|
||||
|
||||
second.accountLock.lock();
|
||||
try {
|
||||
|
||||
while (this.balance < amount) {
|
||||
this.accountCon.await();
|
||||
}
|
||||
this.balance -= amount;
|
||||
target.balance += amount;
|
||||
|
||||
this.accountCon.signalAll();
|
||||
|
||||
}catch (InterruptedException e){
|
||||
throw new RuntimeException();
|
||||
}finally {
|
||||
second.accountLock.unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}finally {
|
||||
first.accountLock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user