Search code examples
javamultithreadingconcurrencyreal-timejava-memory-model

Does synchronized guarantee a thread will see the latest value of a non-volatile variable being modified by another thread?


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...


Solution

  • 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.