Suppose there are 3 threads,
Thread 1 and 2 will increase or decrease a global variable X atomically.
thread 1:
atomic_increase(X)
thread 2:
atomic_decrease(X)
Thread 3 will check if the X is greater than some predefined value and do things accordingly.
thread 3:
if( X > 5 ) {... logic 1 ...}
else {... logic 2 ....}
I think the atomic_xxx
operations are not enough. They can only synchronize the modifications between thread 1 and 2.
What if X
is changed by thread 1 or 2 after thread 3 finishes the comparison and enters logic 1
.
Do I have to use a mutex to synchronize all the 3 threads when modifying or reading the X
?
BTW, logic 1 and logic 2 don't modify the X.
Using Volatile keyword A volatile keyword is a field modifier that ensures that the object can be used by multiple threads at the same time without having any problem. volatile is one good way of ensuring that the Java program is thread-safe.
Barriers. Barriers are a synchronization mechanism that can be used to coordinate multiple threads working in parallel. A barrier allows each thread to wait until all cooperating threads have reached the same point, and then continue executing from there.
Deadlocks, Starvation, Livelock and Race Conditions Deadlocks, starvation, and race conditions are the bane of multithreaded programming and they can bring down any system in which they occur.
In short yes, reads also need to be synchronized in some way, otherwise the risk of inconsistent reads is real. A read performed between the read and write of atomic_increase
will be inconsistent.
However if logic 1
or logic 2
do stuff to X
, your problems doesn't seem to stop right there. I think then you need the concept of a transaction, where it starts with a read (the X > 5
thing) and then ends with a write (logic 1
or logic 2
).
Yes, And the Answer is happens before
link, Lets say Thread-1
started executing atomic_increase
method. It will hold the lock
and enter the synchronized
block to update X
.
private void atomic_increase() {
synchronized (lock) {
X = X + 1; // <-- Thread-1 entered synchronized block, yet to update variable X
}
}
Now, for Thread-3
to run the logic, it needs to read the variable X
, and if it is not synchronized
(on the same monitor), the variable X
read can be an old value since it may not yet updated by Thread-1
.
private void runLogic() {
if (X > 5) { // <-- Reading X here, can be inconsistent no
happens-before between atomic_increase and runLogic
} else {
}
}
We could have prevented this by maintaining a happens-before
link between atomic
operation and run_logic
method. If the runLogic
is synchronized
(on the same monitor) , then it would have to wait until the variable X
to be updated by the Thread-1
. So we are guaranteed to get the last updated value of X
private void runLogic() {
synchronized (lock) {
if (X > 5) { // <-- Reading X here, will be consistent, since there
is happens-before between atomic_increase and runLogic
} else {
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With