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

StackOverflow https://stackoverflow.com/questions/22706739

Question

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

Was it helpful?

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.

OTHER TIPS

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

No.There is no guarantee that Thread B will gives latest value always.Since increment() is non-synchronized method and value() is synchronized method.
Since

While a thread is inside a synchronized method of an object, all other threads that wish to execute this synchronized method or any other synchronized method of the object will have to wait.

This restriction does not apply to the thread that already has the lock and is executing a synchronized method of the object. Such a method can invoke other synchronized methods of the object without being blocked. The non-synchronized methods of the object can of course be called at any time by any thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top