Lock Reservation

This is blog 7 in the OpenJ9 locking/synchronization series (blog 1). It covers an optimization related to the object-monitors (blog 2), which are used to enforce synchronization for the Java objects. Before reading this blog, one needs to have knowledge about the object-monitors. Please read the blog on the object-monitors before reading this blog.

In OpenJ9, lock reservation is an optimization of thin/flat locks, which are represented by the lock-words in the object-monitors. It exploits the thread locality of Java object locks. It reduces the need for atomic compare-and-swap (CAS) operations that stall the CPU.

Thin/flat lock (lock-word) overview

Thin/flat locks (lock-words) are optimized for the following scenarios:

  • Locking an unlocked object.
  • Recursively locking an object.
  • Locking an object that is only briefly contended.

During analysis of benchmarks, it was noticed that most objects are only ever locked by a single thread (> 60%), and most locking operations are “first repetitions” i.e. objects are repeatedly locked by the first thread that locks them (75-99%) [1]. This is an example of thread locality.

Thread locality analysis suggests that we should optimize for an object being repeatedly locked by the same thread. If an object is reserved for a thread, then the thread can lock the object without using the CAS operation.

All objects are initially unreserved. Who decides to reserve objects for a thread? The JIT determines the objects to reserve using code analysis.

  1. Which objects are reservable? Classes with many small synchronized methods.
  2. Which methods should reserve on enter? Hot synchronized methods containing many locking operations.

A bit (RES) is introduced in an object-monitor’s lock-word (thin/flat lock) to state if an object is reserved.

Thin/flat lock (lock-word) with lock reservation

The best case for locking an unlocked object becomes:

  1. Read the lock-word.
  2. If ((thread ID | RES) == lock-word) then increment the count.

No atomic compare-and-swap operation used.

The best case for unlocking an object becomes:

  1. Decrement the count.

Other threads cannot modify an object-monitor while it is reserved for a specific thread. So, the lock reservation needs to be cancelled in order to allow other threads to access an object-monitor. Cancelling a lock reservation is very expensive. The process of cancelling a lock reservation is shown in the figure below.

Cancelling of a lock reservation

Ultimately, the efficiency of the lock reservation feature depends on the JIT’s ability to pin-point the reservable objects which won’t need the lock reservation to be cancelled.

OpenJ9 command line options for lock reservation:

  • -XlockReservation (enable lock reservation)
  • -Xjit:reservingLocks (enable reserving locks for hot methods on classes that can be reserved)
  • -Xjit:reserveAllLocks (enable reserving locks for all classes and methods; debug only)

[References] The following works cover the concept of lock reservation:

  1. Lock Reservation: Java Locks Can Mostly Do Without Atomic Operations by Kiyokuni Kawachiya, Akira Koseki, and Tamiya Onodera.
  2. Lock Reservation for Java Reconsidered by Tamiya Onodera, Kikyokuni Kawachiya, and Akira Koseki.


Suggested Readings

The next blog in the OpenJ9 locking/synchronization series covers the class-specific spin parameters (blog 8) feature, which allows the spin parameters to be varied for all the instances of a class.

If you missed the previous blog in this series, it covers the lock nursery (blog 6) feature, which reduces the memory usage by optimizing the memory allocation for the object-monitors’ lock-words.

[Note] Not all the command line options, mentioned above, may have customer support. Some options are only available for experimental work.

1 Reply to “Lock Reservation”

Leave a Reply