Why Two Simple Alarms Cause a Java Deadlock – Lessons on Synchronized Locks
A Java program that creates two alarm threads and a single shared object ends up in a deadlock because each thread holds its own lock while waiting for the other's lock, illustrating the pitfalls of careless synchronized usage.
Little Black, a programmer, sets two alarms to avoid missing time, and when either alarm rings he wakes up and turns off both alarms.
Both Clock and BlackBro classes are defined with synchronized methods to protect against interference.
public class Clock {
private BlackBro blackBro;
public void setBlackBro(BlackBro blackBro) {
this.blackBro = blackBro;
}
public synchronized void ring() {
System.out.println(Thread.currentThread() + " Clock.ring...");
blackBro.wake();
}
public synchronized void close() {
System.out.println(Thread.currentThread() + " Clock.close...");
}
} public class BlackBro {
private Clock[] clocks;
public void setClocks(Clock[] clocks) {
this.clocks = clocks;
}
public synchronized void wake() {
System.out.println(Thread.currentThread() + "BlackBro.wake...");
for (Clock clock : clocks) {
clock.close();
}
}
}The main method creates two Clock instances and a single BlackBro, registers them, and starts two threads that invoke Clock.ring().
public static void main(String[] args) {
Clock clock1 = new Clock();
Clock clock2 = new Clock();
BlackBro blackBro = new BlackBro();
clock1.setBlackBro(blackBro);
clock2.setBlackBro(blackBro);
blackBro.setClocks(new Clock[]{clock1, clock2});
// sleep...
Thread t1 = new Thread(clock1::ring);
Thread t2 = new Thread(clock2::ring);
t1.start();
t2.start();
}Running the program results in both threads printing “Clock.ring...” and “BlackBro.wake...”, then the program hangs.
Analyzing the thread dump with jstack reveals a Java‑level deadlock: each thread holds the monitor of one object while waiting for the monitor of the other.
Found one Java-level deadlock:
=============================
"Thread-0":
waiting to lock monitor 0x0000600003ecc000 (object 0x000000070fc52398, a com.demo.BlackBro),
which is held by "Thread-1"
"Thread-1":
waiting to lock monitor 0x0000600003ec04e0 (object 0x000000070fc50f88, a com.demo.Clock),
which is held by "Thread-0"
Java stack information for the threads listed above:
===================================================The deadlock occurs because each alarm thread acquires its own Clock lock, calls blackBro.wake(), which tries to acquire the BlackBro lock and then close both clocks, requiring the other Clock lock that is held by the opposite thread.
This simple case demonstrates the danger of careless use of synchronized locks and reminds developers to check for deadlocks when a program does not behave as expected.
Xiao Lou's Tech Notes
Backend technology sharing, architecture design, performance optimization, source code reading, troubleshooting, and pitfall practices
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
