Here is a simple example:
private long counter = 0;
// note this method is NOT synchronized
// this will be called by thread A
public void increment() { counter++; }
// note this method IS synchronized
// this will be called by thread B
public synchronized long value() { return counter; }
So I just want to get a good value for counter
, not a stuck value in the cpu cache because the variable is non-volatile. The goal is to NOT make counter volatile so it does NOT impact thread A doing the increments, but only thread B, which I don't care, when it reads the variable.
Just for the record, I plan to read the value of counter
from thread B when thread A has already finished anyways...
When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
The volatile keyword is useful in two multi-threading scenarios: When only one thread writes to the volatile variable and other threads read its value. Thus, the reading threads see the latest value of the variable.
If it is accessed only from synchronized blocks is not needed the volatile keyword. Synchronized guarantees that changes to variables accessed inside the synchronized block are visible to all threads entering a synchronized block.
In Java, if a synchronized method contains a call to a non-synchronized, can another method still access the non-synchronized method at the same time? Yes. Other methods can access non-synchronized methods.
No, the synchronized block in thread B does not ensure that it will read the actual current value of counter
. You would need synchronized blocks in both threads to do that. From a practical perspective, your code ensures that the processor running thread B invalidates its cache and reads the value of counter
from main memory, but it does not ensure that the processor running thread A flushes its current value to main memory, so the value in main memory may be stale.
Since using a volatile variable is cheaper than synchronized blocks in both threads, making counter
volatile is likely the correct solution. This is what volatile variables are for.
Edit: if thread A is going to complete before thread B reads the final value, you could enclose the entire execution of thread A in a single synchronized block or have thread B join thread A before reading the counter, ensuring that thread A completes before the counter is read. That would result in one cache flush at the end of Thread A's execution, which would have negligible impact on performance.
long
assignment is not guaranteed to be atomic, so not only could B read a stale value, it could also read a half written value.
For proper visibility you need to make counter volatile. Note that even then, calling increment n times from several threads may not increment counter by n.
You could use an AtomicLong
to simply since your problem.
No, synchornized
only guarantees visibility of changes that were made within synchronized blocks of the same lock:
synchornized(this) {
counter++;
}
or before them (as defined by transitive nature of happens-before relationship):
// Thread A
counter++
synchronized (this) {
finished = true;
}
// Thread B
synchonized (this) {
if (finished) {
// you can read counter here
}
}
Note, however, that counter
is guaranteed to be visibile if you read it after you positively determined that Thread A has finished (for example, using join()
):
threadA.join();
// you can read counter here
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