You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

Compliant Solution (immutable member accessed using synchronization)

If the Helper class is immutable, it cannot be changed after it is initialized and will always be properly constructed. However, this does not prevent a thread from accessing the helper field of class Foo before the Helper instance is assigned.

According to Arnold et al. [[JPL 06]], 14.10.2. Final Fields and Security:

... indeed you can use final fields to define immutable objects. There is a common misconception that shared access to immutable objects does not require any synchronization because the state of the object never changes. This is a misconception in general because it relies on the assumption that a thread will be guaranteed to see the initialized state of the immutable object, and that need not be the case. The problem is that, while the shared object is immutable, the reference used to access the shared object is itself shared and often mutable. Consequently, a correctly synchronized program must synchronize access to that shared reference, but often programs do not do this, because programmers do not recognize the need to do it. For example, suppose one thread creates a String object and stores a reference to it in a static field. A second thread then uses that reference to access the string. There is no guarantee, based on what we've discussed so far, that the values written by the first thread when constructing the string will be seen by the second thread when it accesses the string.

In this compliant solution, the Helper class is made immutable. However, the reference to the immutable Helper object instance is shared and as a result, mutable. Consequently, there is an additional requirement of synchronizing the methods of class Foo to ensure that no thread sees a partially initialized helper.

class Foo {
  private Helper helper;

  public synchronized Helper getHelper() {
    return helper;
  }

  public synchronized void initialize() {
    helper = new Helper(42);
  }
}

// Immutable Helper
public class Helper {
  private final int n;

  public Helper(int n) {
    this.n = n;
  }
  // ...
}
  • No labels