Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 785
JohnPristine Avatar asked Mar 28 '14 07:03

JohnPristine


People also ask

What will happens if a synchronized method is called?

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.

How can volatile Make sure the thread will get the latest result?

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.

Is volatile required with synchronized?

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.

Can a synchronized method call a non synchronized method?

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.


3 Answers

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.

like image 59
Warren Dew Avatar answered Oct 20 '22 05:10

Warren Dew


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.

like image 45
assylias Avatar answered Oct 20 '22 07:10

assylias


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
like image 1
axtavt Avatar answered Oct 20 '22 06:10

axtavt