十三、Java并发 Java Java.util.concurrent.Locks
对于Java 来讲,锁 ( Lock ) 是一种比标准同步块 ( synchronized block ) 更灵活,更复杂的线程同步机制。
其实,Java 1.5 就已经存在 Lock 接口了。这个 Lock 接口在 java.util.concurrent.lock 包中定义,提供了大量的锁操作。
本文中,我们将讲解 Lock 接口的不同实现并介绍如何在应用程序中使用锁。
锁 ( lock ) 和同步块 ( synchronized block ) 之间的差异
使用synchronized 块和使用 Lock API 之间几乎没有区别:
-
同步块完全包含在方法中 : 在独立的方法中,我们可以使用 Lock 提供的 lock() 和 unlock() 实现锁和解锁操作。
-
同步块不支持公平竞争,任何线程都可以获取释放的锁定,且不能指定优先级。但锁 ( Lock ) 就不一样了,可以通过指定公平属性来实现 Lock 中的公平性。这可以确保最长的等待线程被授予锁定权限。
-
如果线程无法访问同步块,则会阻塞该线程。Lock 则提供了 tryLock() 方法。线程只有在可用且不被任何其他线程保持时才获取锁定。这减少了线程等待锁定的阻塞时间。
-
处于 「 等待 」 状态以获取对同步块的访问的线程不能被中断。Lock 提供了一个 lockInterruptibly() 方法,可用于在等待锁定时中断线程。
从上面的对比来看,同步块的所有机制,锁 ( Lock ) 都有相应的 API 对应。
Lock API
我们来看看 Lock 接口提供了哪些方法:
| 方法 | 说明 |
|---|---|
| void lock() | 尝试获取锁(如果可用),如果锁不可用,则线程会被阻塞,直到锁被释放 |
| oid lockInterruptibly() | 类似于 lock(),但它允许被阻塞的线程被中断并通过抛出的 java.lang.InterruptedException 恢复执行 |
| boolean tryLock() | lock() 方法的非阻塞版本,它会立即尝试获取锁定,如果锁定成功则返回 true |
| boolean tryLock(long timeout, TimeUnit timeUnit) | 类似于 tryLock(),但它可以指定超时,达到超时之后就会自动放弃获取锁 |