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 带来怎样不同的表现。