Java Object Structure
In the JVM, objects are organized into three memory regions:
-
Object Header
- Mark Word: Stores object hash code, generation age, and lock status flags. This field is dynamically reused based on the object's state.
- Klass Pointer: A reference to the class metadata, enabling the JVM to determine the object's class.
-
Instance Data
- Contains the actual field values of the object, encluding inherited data from parent classes.
-
Padding
- Ensures object alignment to 8-byte boundaries as required by the JVM. An empty object occupies 8 bytes due to this padding.
Synchronized Usage Scenarios
The synchronized keyword in Java can be applied in three primary ways:
-
Instance Methods: Acquires a lock on the current instance (
this) java public class SynchronizedExample { public synchronized void method() { // Critical section } } -
Static Methods: Acquires a lock on the class's Class object java public class SynchronizedExample { public static synchronized void staticMethod() { // Critical section } }
-
Code Blocks: Acquires a lock on a specified object java public class SynchronizedExample { public void method() { synchronized (new Object()) { // Critical section } } }
Memory Model Guarantees
Ordering
The JVM ensures that as-if-serial semantics are maintained. While optimizations may reorder instructions, single-thread execution results remain consistent, and data dependencies are preserved.
Visibility
The Java Memory Model (JMM) defines visibility rules for shared variables, ensuring changes are properly propagated between threads.
Atomicity
Synchronization guarantees atomicity by ensuring only one thread can execute a critical section at a time.
Key Synchronized Features
Reentrancy
Synchronized locks are reentrant, allowing a thread to acquire the same lock multiple times. A counter tracks lock acquisition depth, decrementing upon exit and releasing when it reaches zero.
Non-Interruptibility
Once a thread acquires a lock, other threads waiting for that lock cannot be interrupted until the lock is released.
Implementation Details
Bytecode Analysis
Examining the bytecode reveals how synchronization is implemented:
public class SynchronizedExample {
public synchronized void method() {
synchronized (new Object()) {
// Critical section
}
}
}
Disassembling with javap -p -v -c shows:
- For synchronized methods: The
ACC_SYNCHRONIZEDflag is set - For synchronized blocks:
monitorenterandmonitorexitinstructions are used
Monitor Objects
The core of Java synchronization is the monitor mechanism, implemented in C++ as ObjectMonitor. Key fields include:
_count: Lock acquisition count_recursions: Reentrancy counter_owner: Current lock holder_WaitSet: Threads waiting on the monitor_EntryList: Threads blocked waiting for the monitor
Lock Evolution Process
Biased Locking (Java 6+ default)
- First thread to access an object "biases" the lock
- Thread ID is stored in the Mark Word
- Subsequent accesses by the same thread require no synchronization
- CAS operations are used for lock acquisition
Lightweight Locking
- If no bias exists or bias is revoked, lightweight locking is attempted
- A lock record is created in the thread's stack frame
- CAS operations are used to update the object's Mark Word
- On failure, lock state is upgraded
Spin Locking
- If lightweight locking fails, the thread spins briefly (default 10 times)
- Avoids context switching by keeping the thread active
- Reduces overhead compared to full thread blockign
Heavyweight Locking
- After spin threshold is exceeded, the lock becomes heavyweight
- Threads are blocked and require OS intervention for wakeup
- Involves kernel transitions, which are resource-intensive
Synchronized vs. Lock Interface
Key differences:
- Nature:
synchronizedis a JVM keyword;Lockis a JDK interface - Lock Release:
synchronizedis automatic;Lockrequires manual release - Interruptibility:
synchronizedis non-interruptible;Locksuppotrs interruption - Status Checking:
Lockallows checking if a thread holds the lock - Fairness:
synchronizedis non-fair;ReentrantLockcan be configured for fairness - Read Locks:
Lockinterfaces support read-write locks for improved concurrency
The choice between synchronized and Lock depends on specific use cases and requirements.