It is important to note that neither
Thread.yieldhave any synchronization semantics. In particular, the compiler does not have to flush writes cached in registers out to shared memory before a call to
Thread.yield, nor does the compiler have to reload values cached in registers after a call to
Code that bases its concurrency safety on thread suspension or yields to processes that
- Flush cached registers,
- Reload any values,
- Or provide any relationships when execution resumes,
is incorrect and is consequently disallowed. Programs must ensure that communication between threads has proper synchronization, happens-before, and safe publication semantics.
Noncompliant Code Example (
This noncompliant code attempts to use the nonvolatile primitive Boolean member
done as a flag to terminate execution of a thread. A separate thread sets
true by calling the
The compiler, in this case, is free to read the field
this.done once and to reuse the cached value in each execution of the loop. Consequently, the
while loop might never terminate, even when another thread calls the
shutdown() method to change the value of
this.done [JLS 2013]. This error could have resulted from the programmer incorrectly assuming that the call to
Thread.sleep() causes cached values to be reloaded.
Compliant Solution (Volatile Flag)
This compliant solution declares the flag field
volatile to ensure that updates to its value are made visible across multiple threads:
The volatile keyword establishes a
Compliant Solution (
A better solution for methods that call
sleep() is to use thread interruption, which causes the sleeping thread to wake immediately and handle the interruption.
Note that the interrupting thread must know which thread to interrupt; logic for tracking this relationship has been omitted from this solution.
Noncompliant Code Example (
This noncompliant code example contains a
doSomething() method that starts a thread. The thread supports interruption by checking a flag and waits until notified. The
stop() method checks to see whether the thread is blocked on the wait; if so, it sets the flag to true and notifies the thread so that the thread can terminate.
stop() method incorrectly uses the
Thread.getState() method to check whether the thread is blocked and has not terminated before delivering the notification. Using the
Thread.getState() method for synchronization control, such as checking whether a thread is blocked on a wait, is inappropriate. Java Virtual Machines (JVMs) are permitted to implement blocking using spin-waiting; consequently, a thread can be blocked without entering the
TIMED_WAITING state [Goetz 2006]. Because the thread may never enter the
WAITING state, the
stop() method might fail to terminate the thread.
stop() are called from different threads, the
stop() method could fail to see the initialized
thread, even though
doSomething() was called earlier, unless there is a happens-before relationship between the two calls. If the two methods are invoked by the same thread, they automatically have a happens-before relationship and consequently cannot encounter this problem.
This compliant solution removes the check for determining whether the thread is in the
WAITING state. This check is unnecessary because invoking
notifyAll() affects only threads that are blocked on an invocation of
Relying on the
getState() methods for synchronization control can cause unexpected behavior.