Versions Compared

Key

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

...

  • The lock object might be accessible to hostile code that can acquire the lock and hold it indefinitely. We recommend that locks not be accessible outside of their containing packageLocks should be made inaccessible outside the package they are declared in.
  • A non-final field referring to a lock object might can be modified to refer to a different lock object. This can cause two critical sections of code that expect to lock on the same object to lock on different objects instead, or, two critical sections intending to lock on different objects may end up locking to lock on the same shared object. This can result in unanticipated outcomes.
  • Any An object that supports the uses dynamic locking, such as through java.util.concurrent.Lock interface ReentrantLock, should not have expose its intrinsic lock used; as so that other code can use it because this may cause confusion and inconsistency during maintainanceintroduce maintenance issues.

Noncompliant Code Example (public nonfinal lock object)

...

This is because the thread that holds a lock on the nonfinal field object can modify the field's value to reference refer to some other object. This might cause two threads that intend to lock on the same field object to actually not lock on the same object, causing different objects, enabling them to execute the two critical sections of code simultaneouslyin an unsafe manner.

Compliant Solution (private and final lock object)

This compliant solution synchronizes using a lock object that is declared as private and final.

Code Block
bgColor#ccccff
private final Integer lock = new Integer(0);

private void doSomething() {
  synchronized(lock) { /* ... */ }
}

// setValue() is disallowed

Noncompliant Code Example (Boolean lock object)

Wiki MarkupThis noncompliant code example uses a {{Boolean}} field for synchronization. However, because the field is non-final, there can be two possible valid values ({{true}} and {{false}}, discounting {{null}}) that a {{Boolean}} can assume. Consequently, any other code that synchronizes on the same value can cause unresponsiveness and deadlocks \[[Findbugs 08|AA. Java References#Findbugs 08]\].

Code Block
bgColor#FFcccc

private Boolean initialized = Boolean.FALSE;
synchronized(initialized) { 
  if (!initialized) {
    // Perform initialization
    initialized = Boolean.TRUE;
  }
}

Code Block
bgColor#FFcccc

private Boolean initialized = Boolean.FALSE;
synchronized(initialized) { 
  if (!initialized) {
    // Perform initialization
    initialized = Boolean.TRUE;
  }
}

Wiki Markup
However, because the field is non-final, there can be two possible valid values ({{true}} and {{false}}, discounting {{null}}) that a {{Boolean}} can assume. Consequently, any other code that synchronizes on the same value can cause unresponsiveness and deadlocks \[[Findbugs 08|AA. Java References#Findbugs 08]\]. Even if the field were final, the code would use the intrinsic lock of {{Boolean.FALSE}} or {{Boolean.TRUE}}, which are accessible throughout the program. 
Even if the field were final, the code would use the intrinsic lock of Boolean.FALSE or Boolean.TRUE, which are accessible throughout the program. Consequently any other code could lock these objects and cause deadlock.

Noncompliant Code Example (Boxed primitive)

...

Consequently, a String constant behaves like a global variable in the JVM. As demonstrated in this noncompliant code example, even if each every instance of an object maintains its own field lock, the field points to a common String constant in the JVM. Trusted code that locks on the same String constant renders all synchronization attempts inadequate. Likewise, hostile code from any other package can exploit this vulnerability.

...

This does not mean that a subclass using getClass() can only synchronize on the Class object of the base class. In fact, it will lock on its own Class object, which may or may not be want the programmer had in mind. The intent should be appropriately documented or annotated.

Compliant Solution (class name qualification)

...

This noncompliant code example uses a nonstatic lock object to guard access to a static field. If two Runnable tasks, each consisting of a thread are started, they will create two instances of the lock object and lock on each separately. This does not prevent either thread from observing an inconsistent value of counter because the increment operation on volatile fields is not atomic in the absence of proper synchronizationof the lock object and lock on each separately.

Code Block
bgColor#FFcccc
class CountBoxes implements Runnable {
  static volatile int counter;
  // ...

  Object lock = new Object();    

  public void run() {
    synchronized(lock) {
      counter++; 
      // ... 
    } 
  }

  public static void main(String[] args) {
    Runnable r1 = new CountBoxes();
    Thread t1 = new Thread(r1);
    Runnable r2 = new CountBoxes();
    Thread t2 = new Thread(r2);
    t1.start();
    t2.start();
  }
}
.start();
    t2.start();
  }
}

This does not prevent either thread from observing an inconsistent value of counter because the increment operation on volatile fields is not atomic in the absence of proper synchronization.

Noncompliant Code Example (method synchronization for static data)

...

This problem usually comes up in practice when refactoring from intrinsic locking to the java.util.concurrent dynamic locking utilities.

Compliant Solution (lock() and unlock())

...

Noncompliant Code Example (collection view)view)

Finally, it is more important to recognize the entities with whom synchronization is required rather than indiscreetly scavenging for variables or objects to synchronize on. This noncompliant code example synchronizes on the view of a synchronized map.

Code Block
bgColor#FFcccc
Map<Integer, String> mmap = Collections.synchronizedMap(new HashMap<Integer, String>());
Set<Integer> sset = mmap.keySet();
synchronized(sset) {  // Incorrectly synchronizes on sset
  for(Integer k : sset) { 
    // Do something 
  }
}

Wiki Markup
When using synchronization wrappers, the synchronization object must be the {{Collection}} object. The synchronization is necessary to enforce atomicity ([CON07-J. Do not assume that a grouping of calls to independently atomic methods is atomic]). This noncompliant code example demonstrates inappropriate synchronization resulting from locking on a Collection view instead of the Collection object itself \[[Tutorials 08|AA. Java References#Tutorials 08]\]. 

Wiki Markup
The Collections class documentation \[[API 06|AA. Java References#API 06]\] saysstates:

It is imperative that the user manually synchronize on the returned map when iterating over any of its collection views... Failure to follow this advice may result in non-deterministic behavior.

...

Code Block
bgColor#ccccff
// ...
Map<Integer, String> mmap = Collections.synchronizedMap(new HashMap<Integer, String>());
synchronized(mmap) {  // Synchronize on mmap, not sset
  for(Integer k : mmap) { 
    // Do something  
  }
}

Finally, it is more important to recognize the entities with whom synchronization is required rather than indiscreetly scavenging for variables or objects to synchronize on.

Risk Assessment

Synchronizing on an incorrect variable can provide a false sense of thread safety and result in nondeterministic behavior.

...