This is an issue when a synchronized block uses a static (class-level) lock but only accesses instance fields. The rule does not apply when the synchronized block also accesses static state, because a static lock is required in that case.
Locks in multi-threaded programming control access to shared data. When a lock protects a field, matching the lock scope to the data scope avoids unnecessary contention.
A class-level lock (a static lock) is shared across all instances of a class. It is appropriate for guarding class-level
(static) fields.
An instance-level lock belongs to a specific object instance. It is appropriate for guarding instance fields.
A static lock does provide mutual exclusion and happens-before visibility for instance fields — the synchronization is correct. However, using a static lock to guard only instance fields forces all threads across all instances to serialize on a single monitor, even when they access independent data. This unnecessary contention reduces throughput without any safety benefit.
In Java, class-level locks are implemented using static fields:
private static final Object LOCK = new Object();
This creates a lock that is shared across all instances of the class.
Using a static lock where an instance lock would suffice causes unnecessary thread contention. In applications with many instances or high thread counts, this can measurably degrade throughput and response times. The broader lock scope serializes work that could safely run in parallel, wasting CPU resources and limiting scalability.
When a synchronized block accesses only instance fields, replace the static lock with an instance-level lock so that each object guards its own state independently.
Do not blindly replace a static lock with an instance lock if the synchronized block accesses both instance and static state. A static lock is required in that case; removing it would leave the static state unprotected.
class Counter {
private static final Object LOCK = new Object();
private int count = 0;
public void increment() {
synchronized(LOCK) { // Noncompliant: static lock guards only instance state
count++;
}
}
}
class Counter {
private final Object lock = new Object();
private int count = 0;
public void increment() {
synchronized(lock) {
count++;
}
}
}