原文地址:https://wiki.openjdk.java.net…
Synchronization and Object Locking (同步和对象锁定)
One of the major strengths of the Java programming language is its built-in support for multi-threaded programs. An object that is shared between multiple threads can be locked in order to synchronize its access. Java provides primitives to designate critical code regions, which act on a shared object and which may be executed only by one thread at a time. The first thread that enters the region locks the shared object. When a second thread is about to enter the same region, it must wait until the first thread has unlocked the object again.
Java 编程语言的次要劣势之一是其对多线程程序的内置反对。能够锁定在多个线程之间共享的对象,以便同步其拜访。Java 提供了用于指定要害代码区域的原语,这些要害代码区域作用于共享对象,并且可能一次只能由一个线程执行。进入该区域的第一个线程将锁定共享对象。当第二个线程行将进入同一区域时,它必须期待,直到第一个线程再次将对象解锁。
In the Java HotSpot™ VM, every object is preceded by a class pointer and a header word. The header word, which stores the identity hash code as well as age and marking bits for generational garbage collection, is also used to implement a thin lock scheme [Agesen99, Bacon98]. The following figure shows the layout of the header word and the representation of different object states.
在 Java HotSpot™VM 中,每个对象后面都有一个类指针和一个 header word。该 header word 存储身份哈希码以及年龄和标记位以进行代际垃圾收集,还用于实现 thin lock 机制 [Agesen99,Bacon98]。下图显示了 header word 的布局以及不同对象状态的示意。
The right-hand side of the figure illustrates the standard locking process. As long as an object is unlocked, the last two bits have the value 01. When a method synchronizes on an object, the header word and a pointer to the object are stored in a lock record within the current stack frame. Then the VM attempts to install a pointer to the lock record in the object’s header word via a compare-and-swap operation. If it succeeds, the current thread afterwards owns the lock. Since lock records are always aligned at word boundaries, the last two bits of the header word are then 00 and identify the object as being locked.
图的右侧阐明了规范锁定过程。只有对象是未锁定的,最初两位的值将为 01。当办法在对象上同步时,该 header word 和指向该对象的指针将存储在以后堆栈帧内的锁定记录 (lock record) 中。而后,VM 尝试通过比拟和替换(compare-and-swap) 操作在对象的 header word 中装置一个指向锁定记录的指针。如果胜利,则以后线程将领有该锁。因为锁定记录始终在字边界对齐,因而 header word 的最初两位为 00,而后将对象标识为已锁定。
If the compare-and-swap operation fails because the object was locked before, the VM first tests whether the header word points into the method stack of the current thread. In this case, the thread already owns the object’s lock and can safely continue its execution. For such a recursively locked object, the lock record is initialized with 0 instead of the object’s header word. Only if two different threads concurrently synchronize on the same object, the thin lock must be inflated to a heavyweight monitor for the management of waiting threads.
如果比拟替换操作因为对象之前被锁定而失败,则 VM 首先测试 header word 是否指向以后线程的办法堆栈。在这种状况下,线程曾经领有对象的锁,能够平安地继续执行它。对于这种递归锁定的对象,将锁定记录初始化为 0 而不是对象的 header word。仅当两个不同的线程同时在同一个对象上同步时,才必须将 thin lock(轻量级锁的一种)收缩到重量级锁(heavyweight monitor),以治理期待的线程。
Thin locks are a lot cheaper than inflated locks, but their performance suffers from the fact that every compare-and-swap operation must be executed atomically on multi-processor machines, although most objects are locked and unlocked only by one particular thread. In Java 6, this drawback is addressed by a so-called store-free biased locking technique [Russell06], which uses concepts similar to [Kawachiya02]. Only the first lock acquisition performs an atomic compare-and-swap to install an ID of the locking thread into the header word. The object is then said to be biased towards the thread. Future locking and unlocking of the object by the same thread do not require any atomic operation or an update of the header word. Even the lock record on the stack is left uninitialized as it will never be examined for a biased object.
thin lock 比收缩锁 (inflated lock,也叫 heavyweight monitor)便宜很多,然而它们的性能受到以下事实的困扰:只管大多数对象只能由一个特定的线程锁定和解锁,但每个比拟替换操作都必须在多处理器计算机上以原子形式执行 (thin lock 的实现原理)。在 Java 6 中,此缺点已通过所谓的“无存储有偏差锁定”(store-free biased locking) 技术 [Russell06] 解决,该技术应用相似于 [Kawachiya02] 的概念。仅第一个锁获取执行一个原子比拟和替换,以将锁定线程的 ID 装置到 header word 中。而后称该对象偏差于该线程。同一线程未来对对象的锁定和解锁不须要任何原子操作或 header word 的更新。甚至堆栈上的锁定记录也不会被初始化,因为对于一个偏差的对象,它将永远不会被查看(biased lock 的实现形式)。
When a thread synchronizes on an object that is biased towards another thread, the bias must be revoked by making the object appear as if it had been locked the regular way. The stack of the bias owner is traversed, lock records associated with the object are adjusted according to the thin lock scheme, and a pointer to the oldest of them is installed in the object’s header word. All threads must be suspended for this operation. The bias is also revoked when the identity hash code of an object is accessed since the hash code bits are shared with the thread ID.
当一个线程在偏差另一个线程的对象上同步时,该偏差必须通过使该对象看起来像它已被惯例形式锁定被撤销 。遍历偏差所有者的堆栈,依据 thin lock 计划调整与对象关联的锁定记录,并在对象的 header word 中装置指向它们中最旧的指针。此操作必须暂停所有线程。 当拜访对象的身份哈希码时,因为此哈希码位与线程 ID 共享,因而该偏差也要被撤销。
Objects that are explicitly designed to be shared between multiple threads, such as producer/consumer queues, are not suitable for biased locking. Therefore, biased locking is disabled for a class if revocations for its instances happened frequently in the past. This is called bulk revocation. If the locking code is invoked on an instance of a class for which biased locking was disabled, it performs the standard thin locking. Newly allocated instances of the class are marked as non-biasable.
明确设计为在多个线程之间共享的对象(例如生产者 / 消费者队列)不适宜于偏差锁。因而,如果某个类的实例的撤销在过来频繁产生,则该类的偏置锁将被禁用。这称为批量撤销(bulk revocation)。如果在禁用了偏差锁的类的实例上调用锁定代码,该锁定代码将执行规范的 thin locking。该类的新调配实例被标记为不可偏差的(non-biasable)。
A similar mechanism, called bulk rebiasing, optimizes situations in which objects of a class are locked and unlocked by different threads but never concurrently. It invalidates the bias of all instances of a class without disabling biased locking. An epoch value in the class acts as a timestamp that indicates the validity of the bias. This value is copied into the header word upon object allocation. Bulk rebiasing can then efficiently be implemented as an increment of the epoch in the appropriate class. The next time an instance of this class is going to be locked, the code detects a different value in the header word and rebiases the object towards the current thread.
一种相似的机制,称为批量重偏差 (bulk rebiasing),能够优化类对象被不同线程锁定和解锁但绝不并行的状况。它使类的所有实例的偏差有效,而不会禁用偏差锁定。类中的一个 epoch 值用作批示偏差有效性的工夫戳。在调配对象时,此值将复制到 header word 中。而后, 批量重偏差能够被高效实现为在适当的类中减少 epoch 值。下次此类的实例将被锁定时,代码将在 header word 中检测到一个不同的 epoch 值,并将该对象偏差以后线程。
Source Code Hints (源代码提醒)
Synchronization affects multiple parts of the JVM: The structure of the object header is defined in the classes oopDesc and markOopDesc, the code for thin locks is integrated in the interpreter and compilers, and the class ObjectMonitor represents inflated locks. Biased locking is centralized in the class BiasedLocking. It can be enabled via the flag -XX:+UseBiasedLocking and disabled via -XX:-UseBiasedLocking. It is enabled by default for Java 6 and Java 7, but activated only some seconds after the application startup. Therefore, beware of short-running micro-benchmarks. If necessary, turn off the delay using the flag -XX:BiasedLockingStartupDelay=0.
同步影响 JVM 的多个局部:对象头 (object header) 的构造在 oopDesc 和 markOopDesc 类中定义,thin locks 的代码集成在解释器和编译器中,而 ObjectMonitor 类则示意收缩锁。偏置锁定集中在 BiasedLocking 类中。能够通过标记 -XX:+UseBiasedLocking 启用它,并通过 -XX:-UseBiasedLocking 禁用它。默认状况下,Java 6 和 Java 7 启用了此性能,但在应用程序启动后仅激活了几秒钟。因而,提防短期运行的微基准测试。如有必要,请应用标记 -XX:BiasedLockingStartupDelay=0 敞开提早。
References (参考)
[Agesen99] O. Agesen, D. Detlefs, A. Garthwaite, R. Knippel, Y. S. Ramakrishna, D. White: An Efficient Meta-lock for Implementing Ubiquitous Synchronization. In Proceedings of the ACM SIGPLAN Conference on Object-Oriented Programming, Systems, Languages, and Applications, pages 207-222. ACM Press, 1999. doi:10.1145/320384.320402
[Bacon98] D. F. Bacon, R. Konuru, C. Murthy, M. Serrano: Thin Locks: Featherweight Synchronization for Java. In Proceedings of the ACM SIGPLAN Conference on Programming Language Design and Implementation, pages 258-268. ACM Press, 1998. doi:10.1145/277650.277734
[Kawachiya02] K. Kawachiya, A. Koseki, T. Onodera: Lock Reservation: Java Locks can Mostly do without Atomic Operations. In Proceedings of the ACM SIGPLAN Conference on Object-Oriented Programming, Systems, Languages, and Applications, pages 130-141. ACM Press, 2002. doi:10.1145/582419.582433
[Russel06] K. Russell, D. Detlefs: Eliminating Synchronization-Related Atomic Operations with Biased Locking and Bulk Rebiasing. In Proceedings of the ACM SIGPLAN Conference on Object-Oriented Programming, Systems, Languages, and Applications, pages 263-272. ACM Press, 2006. doi:10.1145/1167473.1167496