Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Changed to Applicability, corrected some links and updated the references to Java 7

According to the Java Language Specification [JLS 20052011], Section 8 §8.3.1.4, "volatile Fields","

A field may be declared volatile, in which case the Java memory model (§17) Memory Model ensures that all threads see a consistent value for the variable (§17.4).

This visibility guarantee applies only to primitive fields and object references. Programmers commonly use imprecise terminology and speak about "member objects." For the purposes of this visibility guarantee, the actual member is the object reference; the objects referred to (hereafter known as the referents) by volatile object references are beyond the scope of the visibility guarantee. Consequently, declaring an object reference to be volatile is insufficient to guarantee that changes to the members of the referent are visible. That is, a thread may fail to observe a recent write from another thread to a member field of such an object referent. Furthermore, when the referent is mutable and lacks thread-safety, other threads might see a partially constructed object or an object in a (temporarily) inconsistent state [Goetz 2007]. However, if the referent is immutable, declaring the reference volatile suffices to guarantee visibility of the members of the referent. Consequently, programmers must not use the volatile keyword to guarantee visibility to mutable objects; use of the volatile keyword to guarantee visibility only to primitive fields, object references, or fields of immutable object referents is permitted.

...

The root of the problem is that the thread that calls setFirst() and the thread that calls getFirst() lack a happens-before  relationship. A happens-before relationship exists between a thread that writes to a volatile variable and a thread that subsequently reads it. However, setFirst() and getFirst() only read from a volatile variable—the variable—the volatile reference to the array; neither method writes to the volatile variable.

...

AtomicIntegerArray guarantees a happens-before relationship between a thread that calls atomicArray.set() and a thread that subsequently calls atomicArray.get().

...

Synchronization establishes a happens-before relationship between threads that synchronize on the same lock. In this case, the thread that calls setFirst() and the thread that subsequently calls getFirst() both synchronize on the Foo instance, so visibility is guaranteed.

...

The volatile-read, synchronized-write technique uses synchronization to preserve atomicity of compound operations, such as increment, and provides faster access times for atomic reads. However, it does not work with mutable objects because the visibility guarantee provided by volatile extends only to the field itself (the primitive value or object reference); the referent (and hence the referent's members) is excluded from the guarantee. Consequently, the write and a subsequent read of the property lack a happens-before relationship.

This technique is also discussed in VNA02-J. Ensure that compound operations on shared variables are atomic.

...

Because DateFormat is not thread-safe [API 20062011] Class DateFormat, the value for Date returned by the parse() method might fail to correspond to the str argument.

...

This compliant solution creates and returns a new DateFormat instance for each invocation of the parse() method [API 20062011] Class DateFormat.

Code Block
bgColor#ccccff
final class DateHandler {
  public static java.util.Date parse(String str) throws ParseException {
    return DateFormat.getDateInstance(DateFormat.MEDIUM).parse(str);
  }
}

...

This compliant solution makes DateHandler thread-safe by synchronizing statements within the parse() method [API 20062011] Class DateFormat.

Code Block
bgColor#ccccff
final class DateHandler {
  private static DateFormat format =
    DateFormat.getDateInstance(DateFormat.MEDIUM);

  public static java.util.Date parse(String str) throws ParseException {
    synchronized (format) {
      return format.parse(str);
    }
  }
}

...

Code Block
bgColor#ccccff
final class DateHandler {
  private static final ThreadLocal<DateFormat> format = new ThreadLocal<DateFormat>() {
    @Override protected DateFormat initialValue() {
      return DateFormat.getDateInstance(DateFormat.MEDIUM);
    }
  };
  // ...
}

Exceptions

Applicability

Incorrectly assuming that declaring a field volatile guarantees the visibility of a referenced object's members can cause threads to observe stale or inconsistent values.

CON50-EX0: Technically, strict immutability of the referent is a stronger condition than is fundamentally required for safe visibility. When it can be determined that a referent is thread-safe by design, the field that holds its reference may be declared volatile. However, this approach to using volatile decreases maintainability and should be avoided.

Risk Assessment

Incorrectly assuming that declaring a field volatile guarantees the visibility of a referenced object's members can cause threads to observe stale or inconsistent values.

Guideline

Severity

Likelihood

Remediation Cost

Priority

Level

CON50-JG

medium

probable

medium

P8

L2

Bibliography

[API 20062011]

Class java.text. DateFormat

[Goetz 2007]

Pattern #2: "One-time safe publication"

[JLS 20052011] 

§8.3.1.4, volatile Fields

[Miller 2009]

Mutable Statics

 

...

Image Modified