13-在同步代码块中使用锁机制
2.4 在同步代码块中使用锁机制
除了 synchronized
之外,Java还提供了其他保护同步代码块的机制。其中 Lock
机制(在 java.util.concurrent.locks
包中定义了该机制)是一类比 synchronized
机制更加强大和灵活的机制。该接口目前也有了一些相应的实现(如 ReentrantLock
类)。使用 Lock
机制可以带来以下好处。
- 构建同步代码更加灵活。关键词
synchronized
仅能作用在一段结构化代码中。通过Lock
接口,你可以在更加复杂的代码结构下访问临界区代码。 - 通过
Lock
接口可以获得其他由synchronized
关键词所不能提供的功能特性,比如tryLock()
方法。通过该方法,线程可以及时知道其他线程当前是否已经持有锁,如果当前线程尝试获取锁失败,则该方法将返回false
。如果此时使用的是synchronized
关键词,线程A希望执行临界区的代码,而在此同时线程B已经正在执行,那么线程A将在线程B执行完毕前保持线程挂起。如果此时使用的是tryLock
方法,那么线程将会立即获得一个Boolean
类型的返回值,以获知当前是否已经有其他线程在执行临界区代码。 - 通过
ReadWriteLock
接口可以实现读写锁分离,即允许同时执行多个读锁而单个写锁与其他锁互斥。 Lock
接口在性能表现上比synchronized
关键词更加优越。
在 ReentrantLock
类构造函数的参数中包含一个名为 fair
的 boolean
变量,开发者可以通过该变量为锁设置不同的策略模式。若值为 false
(也是默认设置)时则当前锁策略为非公平锁策略。在非公平模式下,如果有多个线程同时请求同一个锁,那么该锁将随机分配给其中的一个线程。如果该策略设置为 true
,则表示当前策略为公平锁策略。在该策略下,如果当前有多个线程在等待同一把锁,则等待时间最长的线程将获得锁。以上介绍的策略仅用于 lock()
和 unlock()
两个方法,由于 tryLock()
方法不会使线程进入休眠状态,因此该设置不会作用在 Lock
接口的 tryLock()
方法上。
本节将告诉读者如何通过 Lock
接口及其实现类 ReentrantLock
实现临界区代码。我们将使用程序模拟一个打印队列,在这里你也将了解到公平锁的配置能给 Lock
带来怎样不同的表现。