Synchronized Method Acquires Second Lock
ID |
java.synchronized_calls_synchronized |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
CWE:833, concurrency, reliability |
Description
Reports synchronized methods that contain a synchronized block on a different monitor object. Holding two locks simultaneously creates a lock-ordering dependency: if another code path acquires the same two locks in the opposite order, both threads deadlock permanently.
Rationale
A synchronized method implicitly locks on this. If it also acquires a second lock via synchronized(other), two locks are held at the same time. Deadlock occurs when another thread holds other and tries to enter the same synchronized method (acquiring this).
// Bad -- two locks held simultaneously
public synchronized void transfer(Account other) {
synchronized (other) {
// if 'other' also calls transfer(this), deadlock
}
}
Remediation
Use a consistent lock ordering, a single coarser lock, or java.util.concurrent utilities:
// Good -- consistent ordering by account ID
public void transfer(Account other) {
Account first = this.id < other.id ? this : other;
Account second = this.id < other.id ? other : this;
synchronized (first) {
synchronized (second) {
// safe -- always same order
}
}
}