The synchronized
keyword in Java provides built-in thread synchronisation by ensuring that only one thread can execute a block of code or method at a time. When a thread attempts to enter a synchronized
block, it must first acquire the monitor associated with the specified object.
Two Forms of Synchronisation
1. Synchronized Methods
public synchronized void method() {
// Only one thread can execute this at a time
}
public static synchronized void staticMethod() {
// Locks on the Class object
}
When a method is declared synchronized
:
- Instance methods lock on the instance (
this
) - Static methods lock on the
Class
object in the metaspace - The entire method body is the critical section
2. Synchronized Blocks
public void method() {
synchronized(lockObject) {
// Only one thread can execute this at a time
// for this specific lockObject
}
}
Synchronized blocks offer more flexibility:
- You can specify which object to lock on
- Allows finer-grained locking (shorter critical sections)
- Multiple locks can be used within the same method
How Synchronisation Works
When a thread enters a synchronized
block or method:
- Attempts to acquire the monitor of the specified object
- If unlocked or already owned by this thread and only this thread (reentrant):
- Acquires the lock immediately
- Mark Word transitions to Lightweight Lock state (00)
- If locked by another thread:
- Thread blocks and waits
- Mark Word inflates to Heavyweight Lock state (10)
- Thread is added to the ObjectMonitor’s entry set
When the thread exits the synchronized
block:
- Releases the monitor
- If there are waiting threads, only one is
unparked
to acquire the lock - If no contention, lock may deflate back to unlocked state
Reentrant Locking
Java’s synchronized
is reentrant, meaning a thread that already owns a monitor can acquire it again:
public synchronized void outer() {
inner(); // Same thread can enter
}
public synchronized void inner() {
// This works! Thread already owns the monitor
}
Wait/Notify Mechanism
The synchronized
keyword enables the wait/notify protocol for thread coordination:
synchronized(sharedObject) {
while (!condition) {
sharedObject.wait(); // Releases lock and waits
}
// Condition met, proceed
sharedObject.notify(); // Wake one waiting thread
}
Key methods (Can be called while holding the monitor):
wait()
- Releases the monitor and transitions into waiting state until notifiednotify()
- Wakes up a random thread waiting on this monitornotifyAll()
- Wakes up all threads waiting on this monitor
When wait()
is called:
- The lock must inflate to Heavyweight (ObjectMonitor needed)
- Thread is moved from entry list to wait set
- Monitor is released
- Thread goes into waiting state and only wakes upon
notify()
- Upon
notify()
, thread moves back to entry list to reacquire lock