Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: general edit

Reads of shared primitive variables may not observe the latest writes to them. It is important to ensure that the accesses see the value of the latest writes. If this is not done, multiple threads may observe stale values of the shared variables and fail to act accordingly. Visibility of latest values can be ensured using volatile or synchronization.

The use of volatile is recommended under a very restrictive set of conditions:

  • A write to a variable does not depend on its current value
  • The write is not involved with writes of other variables

Accesses of primitive variables are atomic, except for the 64-bit long and double variables; see CON25-J. Ensure atomicity when reading and writing 64-bit values for information on sharing long and double variables among multiple threads.

If a shared primitive variable has these characteristics:

  • A write to a variable does not depend on its current value
  • The write is not involved with writes of other variables

Wiki Markup
Then the variable should be declared as {{volatile}} \[[Goetz 06|AA. Java References#Goetz 06]\]. If this is not done, multiple threads may observe stale values of the shared variables and fail to act accordingly. 

Noncompliant Code Example

...

Compliant Solution (volatile)

This compliant solution qualifies declares the done flag as volatile so that updates are visible to other threads.

...

This compliant solution uses the this object's intrinsic lock of the Class object to ensure thread safety.

Code Block
bgColor#ccccff
final class ControlledStop implements Runnable {
  private boolean done = false;
 
  public void run() {
    while (!isDone()) {
      try {
        // ...
        Thread.currentThread().sleep(1000); // Do something
      } catch(InterruptedException ie) { 
        // handle exception
      } 
    } 	 
  }

  protected synchronized bool isDone() {
    return done;
  }

  protected synchronized void shutdown() {
    done = true;
  }
}

While this is an acceptable compliant solution, it has the following disadvantages compared to marking declaring done as {{volatile:

  • Performance: The intrinsic locks cause threads to block temporarily; volatile incurs no blocking
  • Deadlock: Improper usage use of locks can lead to deadlock. Since deadlocks. Because the use of volatile incurs no blocking, deadlock cannot occur.

However, synchronization is a useful alternative in situations where the volatile keyword is inappropriate, such as if a variable's new value depends on its old value. Refer to CON01-J. Do not assume that composite operations are atomic and CON07-J. Do not assume that a grouping of calls to independently atomic methods is atomic for more details.

Risk Assessment

Failing to ensure visibility of atomically modifiable shared variables can lead to a thread seeing stale values of a variable.

...