Programs must not use instance locks to protect static shared data because instance locks are ineffective when two or more instances of the class are created. Consequently, failure to use a static lock object leaves the shared state unprotected against concurrent access. Lock objects for classes that can interact with untrusted code must also be private and final, as shown in LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code.
Noncompliant Code Example (Nonstatic Lock Object for Static Data)
This noncompliant code example attempts to guard access to the static
counter field using a nonstatic lock object. When two
Runnable tasks are started, they create two instances of the lock object and lock on each instance separately.
This example fails to prevent either thread from observing an inconsistent value of
counter because the increment operation on volatile fields fails to be atomic in the absence of proper synchronization (see VNA02-J. Ensure that compound operations on shared variables are atomic for more information).
Noncompliant Code Example (Method Synchronization for Static Data)
This noncompliant code example uses method synchronization to protect access to a static class
In this case, the method synchronization uses the intrinsic lock associated with each instance of the class rather than the intrinsic lock associated with the class itself. Consequently, threads constructed using different
Runnable instances may observe inconsistent values of
Compliant Solution (Static Lock Object)
This compliant solution ensures the atomicity of the increment operation by locking on a static object:
It is unnecessary to declare the
counter variable volatile when using synchronization.
Using an instance lock to protect static shared data can result in nondeterministic behavior.
Some static analysis tools can detect violations of this rule.