Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: edits

...

Wiki Markup
The use of {{volatile}} is recommended under a very restrictive set of conditions, all of which must be met \[[Goetz 06|AA. Java References#Goetz 06]\]:

  • A write to a variable does not depend on its current value, or it can be ensured that only a single thread ever updates the value
  • The write is not involved with reads or writes of other variablesOnly a single thread ever updates the value
  • Locking is not required for any other reason (all actions are atomic)

Synchronizing the code makes it easier to reason about the its behavior of the code and is frequently, a more secure approach than using volatile. However, it is slightly more expensive and can cause deadlocks when used excessively.

Declaring a variable as volatile or correctly synchronizing the code guarantees that 64-bit primitive variables of type long and double are accessed atomically (see CON25-J. Ensure atomicity when reading and writing 64-bit values for information on sharing long and double variables among amongst multiple threads).

Noncompliant Code Example

...

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

  public void shutdown() {
    done = true;
  }
}

If one thread invokes the shutdown() method to set the flag, it is possible that another thread might not observe this change. Consequently, the second thread may observe that done is still false and incorrectly invoke the sleep() method. In fact, a compiler is allowed to optimize the code if it determines that the value of done is never modified by the same thread, so that the loop never terminateswith the end result being an infinite loop.

Compliant Solution (volatile)

...

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

  public void shutdown() {
    done.set(true);
  }
}

...

While this is an acceptable compliant solution, it has the following shortcomings as compared to the previously suggested ones:

  • Performance: The intrinsic Intrinsic locks cause threads to block temporarily and may introduce some contention; volatile incurs no blocking
  • Deadlock: Excessive synchronization can make the program deadlock prone.

However, synchronization is a more secure alternative in situations where the volatile keyword or an a java.util.concurrent.atomic.Atomic* field is inappropriate, such as if a variable's new value depends on its old value. Refer to CON01-J. Ensure that compound operations on shared variables are atomic for more information.

...