Skip to content
Advertisement

Should the volatile modifier be added to the object wake-up condition variable?

Please check the sample code below:

private volatile int fActiveTestDeathCount;

synchronized void waitUntilFinished() {
        while (fActiveTestDeathCount < testCount()) {
            try {
                wait();
            } catch (InterruptedException e) {
                return; // ignore
            }
        }
    }

The above code can run normally, which is very easy to understand, but why the following code can also run normally?

private int fActiveTestDeathCount;

synchronized void waitUntilFinished() {
    while (fActiveTestDeathCount < testCount()) {
        ...
    }
}

I think that in a multi-threaded execution environment, each thread copies the fActiveTestDeathCount variable. If there is no additional volatile modifier, this variable is invisible to other threads, and the program should not work, but this is not the case.

I try to analyze whether it is that after the thread is awakened, it will automatically invalidate the variables in the thread’s working memory, and then synchronize the data from the main memory? But this requires the support of memory barriers, which makes me a little confused.

Advertisement

Answer

Here volatile is neither required nor sufficient.

Why is it not sufficient? Because it won’t stop a thread from checking fActiveTestDeathCount right before it is modified by another thread and then irrevocably deciding to wait for something that happened right after it checked.

Why is it not required? Because synchronized already establishes a “happens before” relationship among any two threads accessing fActiveTestDeathCount.

The whole point of wait is to provide an atomic “unlock and wait” operation to solve precisely this race condition.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement