前言
相关系列
- 《Java & Lock & 目录》
- 《Java & Lock & 源码》
- 《Java & Lock & 总结》
- 《Java & Lock & 问题》
涉及内容
- 《Java & Lock & Condition & 总结》
- 《Java & Lock & ReentrantLock & 总结》
- 《Java & synchronized & 总结》
Lock(锁)接口源码及机制详解
接口
Lock(锁)接口定义了API层面上锁的概念。谈到锁,我们很容易能联想到关键字synchronized,其是Java在JVM层面上提供的用于在多线程环境下对共享资源进行同步访问的锁实现。因此自然而然地,我们会将锁接口与之进行对比。但实际上如果从功能的角度来说,将两者进行对比是不合适的。因为synchronized关键字是真正能够提供锁功能的实现,而锁接口仅仅是在API层面上对锁进行了定义,并无法提供实际的锁功能。因此两者在维度上是不平等的,如果真的要与synchronized关键字在具体功能上进行对比的话,使用锁接口的经典实现类ReentrantLock(可重入锁)会更合适,因为两者都是基于重入/排它特性的实现。但话虽如此,如果从结构的角度来看,将两者进行对比也并非完全不可行。例如相比synchronized关键字只加不解(其解锁由JVM自动实现,在手动的角度上只有加锁而没有解锁的说法)的结构而言,锁接口将加/解锁都定义为了人为操作。该结构定义使得锁接口实现类的使用变得稍显复杂,因为开发者需要人为保证“加锁后一定解锁,解锁前必须加锁”的行为准则不被破坏,因此锁接口实现类通常都需要搭配try-catch-finally使用。但相对地这也令锁接口实现类在使用上具备了更强的灵活性,使得多个锁域间的交互除了包含外还可以出现如下图般的交叉情况存在。
/**
* {@code Lock} implementations provide more extensive locking operations than can be obtained using
* {@code synchronized} methods and statements. They allow more flexible structuring, may have quite different
* properties, and may support multiple associated {@link Condition} objects.
* 锁实现提供比使用synchronized修饰的方法和语句更广泛的锁操作。它们允许更灵活的结构,可能有完全不同的属性,以
* 及可能支持多关联条件对象。
* <p>
* A lock is a tool for controlling access to a shared resource by multiple threads. Commonly, a lock provides exclusive
* access to a shared resource: only one thread at a time can acquire the lock and all access to the shared resource
* requires that the lock be acquired first. However, some locks may allow concurrent access to a shared resource, such
* as the read lock of a {@link ReadWriteLock}.
* 锁是一个控制通过多线程访问一个共享资源的工具。通常,一个锁提供排斥访问一个共享资源:一个时间只有一个线程可
* 以获得锁并且访问所有的共享资源需要先获得锁。此外,某些锁可能允许并发访问共享资源,例如读写锁的读锁。
* <p>
* The use of {@code synchronized} methods or statements provides access to the implicit monitor lock associated with
* every object, but forces all lock acquisition and release to occur in a block-structured way: when multiple locks are
* acquired they must be released in the opposite order, and all locks must be released in the same lexical scope in
* which they were acquired.
* 同步方法或语句的使用可对任何对象关联的隐式监控锁进行访问,但它逼迫所有锁获取和释放都在一个阻塞结构的方法中
* 发生:当获取多个锁时他们必须按相对的顺序释放(即按获取锁的相反顺序释放,FILO),并且所有锁必须在它们获取的
* (同步块中)按相同的词汇范围(作用域)释放。
* <p>
* While the scoping mechanism for {@code synchronized} methods and statements makes it much easier to program with
* monitor locks, and helps avoid many common programming errors involving locks, there are occasions where you need
* to work with locks in a more flexible way. For example, some algorithms for traversing concurrently accessed data
* structures require the use of "hand-over-hand" or "chain locking": you acquire the lock of node
* A, then node B, then release A and acquire C, then release B and acquire D and so on. Implementations of the
* {@code Lock} interface enable the use of such techniques by allowing a lock to be acquired and released in different
* scopes, and allowing multiple locks to be acquired and released in any order.
* 虽然同步方法和语句的范围机制令其对于监控锁问题变非常简单,并且有助于避免一些涉及锁的常规编程错误,但偶尔你
* 也需要以一种更加灵活的方式使用锁来工作。例如:某些遍历算法并发访问数据结构需要稳步地使用,或者链式加锁:你
* 获取了节点A的锁,然后节点B,然后释放A并获取C,然后释放B获取D等等。锁接口的实现开启了允许锁的获取和释放在
* 不同的域,并且允许多个锁按任意顺序获取和释放的使用方式。
* <p>
* With this increased flexibility comes additional responsibility. The absence of block-structured locking removes the
* automatic release of locks that occurs with {@code synchronized} methods and statements. In most cases, the
* following idiom should be used:
* 随着增长的灵活性带来的额外责任。缺乏阻塞结构的锁移除了同步方法和语句的锁自动释放。在大多数情况中,应该使用
* 以下习语:
* <pre> {@code
* Lock l = ...;
* l.lock();
* try {
* // access the resource protected by this lock
* } finally {
* l.unlock();
* }}</pre>
* <p>
* When locking and unlocking occur in different scopes, care must be taken to ensure that all code that