How Java Synchronization Works: Monitors Explained
Résumé
Pixel’s announcement breaks down Java synchronization through the JVM monitor, showing how synchronized blocks compile to monitorenter and monitorexit while synchronized methods use a different bytecode approach. It also explores blocked threads and Linux waiting primitives, helping the community understand how synchronization protects shared data and what waiting costs.
DEV Community
How Java Synchronization Works: A Quick Walkthrough
One keyword - synchronized - and two threads stop corrupting each other's data. But what did the keyword actually buy you? The JVM spec has a surprisingly small answer: one mechanism, the monitor, and a handful of bytecode instructions. Let's open it up with real javap output, a live look at a blocked thread, and the Linux primitive the JVM leans on when a thread truly has to wait. One construct: the monitor The JVM spec (JVMS 2.11.10) is blunt: "The Java Virtual Machine supports synchronization of both methods and sequences of instructions within a method by a single synchronization construct: the monitor." Every object can act as a monitor. synchronized (lock) { ... } means: enter the monitor associated with lock; only one thread can own it at a time; everyone else waits. That is the entire mechanism - everything else is how it is compiled and what waiting costs. Here is the journey of two threads and one monitor, animated: Two forms, two very different bytecodes A synchronized block and a synchronized method look alike in Java. In bytecode they are nothing alike. This class: public class SyncBytecode {
private final Object lock = new Object();
private int count;
public void incrementBlock() {
synchronized (lock) {
count++;
}
}
public synchronized void incrementMethod() {
count++;
}
}
javap -c on the block form - real output: public void incrementBlock();
Code:
0: aload_0
1: getfield #7 // Field lock:Ljava/lang/Object;
4: dup
5: astore_1
6: monitorenter
7: aload_0
8: dup
9: getfield #13 // Field count:I
12: iconst_1
13: iadd
14: putfield #13 // Field count:I
17: aload_1
18: monitorexit
19: goto 27
22: astore_2
23: aload_1
24: monitorexit
25: aload_2
26: athrow
27: return
Exception table:
from to target type
7 19 22 any
22 25 22 any
Read it closely - there are two monitorexit instructions. One on the normal path (offset 18), one inside a compiler-generated cleanup (offset 24) guarded by an exception-table row of type any. If count++ somehow threw, control would jump to offset 22, the monitor would still be released, and then athrow would rethrow. That is the spec's promise, made visible: "the executing thread enters a monitor, invokes the method itself, and exits the monitor whether the method invocation completes normally or abruptly." A forgotten unlock on the exception path is impossible by construction. The method form? javap -v shows there are no monitor instructions in its code at all - just a flag on the method: public synchronized void incrementMethod();
flags: (0x0021) ACC_PUBLIC, ACC_SYNCHRONIZED
Per the same spec section, "method-level synchronization is performed implicitly, as part of method invocation and return... the ACC_SYNCHRONIZED flag... is checked by the method invocation instructions." The entering and exiting still happen; they are just the JVM's job at the call boundary rather than explicit bytecodes. What waiting looks like A thread that wants a held monitor doesn't spin visibly - it changes state. The Thread.State JavaDoc defines BLOCKED as: "A thread that is blocked waiting for a monitor lock is in this state." You can watch it happen. Two threads, one lock, the holder sleeping inside its critical section: before start: holder=NEW waiter=NEW
while contended: holder=TIMED_WAITING waiter=BLOCKED
waiter got the lock
after finish: holder=TERMINATED waiter=TERMINATED
Real output, one run. The holder is TIMED_WAITING (it is inside Thread.sleep - a timed wait, holding the monitor the whole time; sleep never releases locks). The waiter is BLOCKED - parked on the monitor, making zero progress, until the holder's monitorexit lets it in. Note the distinction the states encode: BLOCKED means "waiting for a monit...

Powered by Readybot.io