Skip to content

Instantly share code, notes, and snippets.

@cspinetta
Last active February 24, 2022 15:45
Show Gist options
  • Save cspinetta/69fe73bb9e9bf17331efb2f9ab29aa9a to your computer and use it in GitHub Desktop.
Save cspinetta/69fe73bb9e9bf17331efb2f9ab29aa9a to your computer and use it in GitHub Desktop.
Synchronization in Java

Object locking implementation in the Java HotSpot VM

The most synchronization idiom in Java is using the synchronized keyword.

The JVM supports synchronization of both methods and sequences of instructions within a method using a single synchronization construct - synchronized - which is built around an internal entity known as the intrinsic lock or monitor lock (The API specification often refers to this entity simply as a "monitor"). Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships to ensure a correct visibility amoung threads.

At bytecode level, the JVM supplies the monitorenter and monitorexit instructions to support such constructs.

At runtime level, in the Java HotSpot VM, every object has a built-in monitor (the so called intrinsic lock or monitor lock) that can be acquired by any thread.

At bytecode level:

  • Each object has one intrinsict lock associated with it.
  • A thread can take the lock of an object.
  • With the monitorenter instruction a thread tries to gain ownership of the monitor associated with a specified object.
  • If another thread already owns the monitor, the current thread waits until the object is unlocked, then tries again to gain ownership.
  • If the current thread already owns the monitor, it increments a counter in the monitor indicating the number of times this thread has entered the monitor.
  • If the monitor is not owned by any thread, the current thread becomes the owner of the monitor, setting the entry count of this monitor to 1.
  • The compiler introduces a try - catch wrapper in order to ensure a monitorexit will be executed for each monitorenter instruction executed whether the method invocation completes normally or abruptly.

At JVM level:

  • Locking is an intrinsic capability each Java object has, regardless the object type.
  • The object's locking state is stored in the object's header. This includes bit flags describing the locking state (i.e. locked / unlocked, entry count) and a reference to the thread which currently owns the monitor.
  • Acquire a monitor:
    • The monitor is acquired by a thread if it succeeds in establishing itself as the object monitor’s owner.
    • This is determined by whether the thread is able to install a reference to itself (a pointer to the internal JavaThread object) in the object’s header.
    • It goes through a series of steps ranging from optimistic to the pessimistic:
      • The first attempt is using CAS operation (which is usually translated into a direct CPU instruction such as cmpxchg).
      • If the monitor is either free or has been previously biased toward this thread the monitor on the object is obtained for the thread and execution can continue immediately.
      • If fails, the JVM will perform one round of spin locking where the thread parks to effectively put it to sleep between retrying the CAS. (openJDK 8 #slow_enter)
      • If these initial attempts fail (signaling a fairly higher level of contention for the monitor) the thread will move itself to a blocked state and enqueue itself in the list of threads vying for the lock and begin a series of spinlocks.
  • Release a monitor:
    • When exiting the critical section through a monitorexit instruction, the owner thread will try to see if it can wake any of the parked threads which may be waiting for the monitor to be released (process known as choosing an 'heir'). This is meant to increase liveliness and to prevent a scenario where threads remain parked while the monitor has already been released (also known as stranding).

Other related topics

  • Biased Locking implemented in the Java HotSpot VM
  • Java ReentrantLock
  • Java memory model / memory visibility / happened-before
  • Double-checked locking pattern

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment