Synchronization 中英文对照翻译


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