OpenJ9 Java Virtual Machine (JVM) implements the synchronization features needed for the Java language. Also, OpenJ9 is a multi-threaded application with virtual machine (VM), garbage collector (GC), just-in-time (JIT) and other native threads which require synchronization. This is the main blog a.k.a blog 1 which summarizes the various data structures and features used to support synchronization internally within OpenJ9 and for the Java language. Synchronization is analogous to locking or usage of locks to manage shared resources between threads. Each OpenJ9 synchronization data structure and feature has a sub-blog where it is discussed in greater detail. For the readers with no background on locks and synchronization, a basic introduction to these topics is here.
All the blogs in the OpenJ9 locking/synchronization series are listed here.
OpenJ9 uses four types of native locks or synchronization data structures:
- GC-spinlocks (J9GCSpinlock; GC – Garbage Collector)
- System-monitors (omrthread_monitor_t)
- Raw-monitors (JVM_RawMonitor*)
- Object-monitors (J9ObjectMonitor)
A system-monitor (blog 2) is used for internal locking between the VM, GC, JIT, and native threads, and to support object-monitors. It is of type omrthread_monitor_t, and includes its own structures and logic. If the logic of a system-monitor cannot avoid suspending a thread, then it defers to the operating system (OS) specific synchronization primitives.
A GC-spinlock (blog 2) is similar to an system-monitor, but it supports a more limited set of functionality and is optimized to be as lightweight as possible. It is only used by the garbage collector (GC).
A raw-monitor (blog 2) is provided to the Java class library code via the JVM_RawMonitor* API. It is essentially an opaque pointer to a system-monitor. JVMTI raw monitors are similar.
An object-monitor (blog 3) supports synchronization at the Java level. Java specifies an object-monitor for each object. A monitor is used to synchronize an object. For example, invoking a synchronized block or synchronized method of an object X uses the object-monitor of object X for synchronization. The object-monitors are of the type J9ObjectMonitor, each with their own structures and logic. If an object-monitor’s logic cannot avoid suspending a thread, then it relies on a system-monitor to do the suspension.
The figure below provides a basic architecture overview with a focus on Java, OpenJ9, OMR and locking.
- The Java component includes the synchronized methods, synchronized blocks, java.lang.Object (wait/notify), java.util.concurrent package and other support for concurrent programming.
- The OpenJ9 component supports the object-monitors and exposes the JVM and JVMTI raw-monitors.
- The OMR thread library supports the system-monitors and the GC-spinlocks.
- The OMR port library provides an API for basic cross-platform operations such as memory allocation, file operations, retrieving system information, signal handling, etc.
Locking/Synchronization features available in OpenJ9:
- Three-tier Spinning
- Adaptive Spinning
- Lock Nursery
- Lock Reservation
- Class-specific Spin Parameters
The three-tier spinning (blog 4) strategy contains three tiers, such that each tier has an incrementally larger wait-interval between attempts to acquire a lock while spinning. Each tier is dependent on two kinds of locking structures/calls: lightweight and heavyweight. Initially, the lightweight structures/calls are used for a specific number of spins. When the spin is exhausted, the heavyweight structures/calls are used, which put the thread into a suspended state that does not utilize the CPU.
The adaptive spinning (blog 5) strategy identifies cases where lock spinning regresses performance and disables spinning for those cases.
The lock nursery (blog 6) reduces memory usage by efficiently storing the thin/flat locks (lock-words) related to the object-monitors.
The lock reservation (blog 7) strategy is an optimization for thin/flat locks (lock-words). It exploits the thread locality of object-monitors and reduces the need for compare-and-swap operations that stall the CPU.
The class-specific spin parameters (blog 8) allow the spin parameters to be varied for all the instances of a class.
- omrthread_rwmutex_t (blog 9): Readers-writer (RW) lock developed using a system-monitor.
- VM Access (blog 10): Synchronization feature for manipulating Java objects within OpenJ9. There are two modes: shared VM access for reading objects and exclusive VM access for writing/editing objects.
- Deadlock Detection, Lock Contention and Locking Performance (blog 11).