此Java教程适用于JDK 8。本页面描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
有关Java SE 9及其后续版本中更新的语言功能的摘要,请参阅Java语言更改。
有关所有JDK版本的新功能、增强功能以及已删除或弃用选项的信息,请参阅JDK版本说明。
同步代码依赖于一种简单的可重入锁。这种类型的锁很容易使用,但有很多限制。更复杂的锁机制由 java.util.concurrent.locks
包支持。我们不会详细讨论这个包,而是专注于它最基本的接口 Lock
。
Lock
对象的工作方式与 synchronized 代码使用的隐式锁非常相似。与隐式锁一样,Lock
对象一次只能被一个线程拥有。Lock
对象还通过与之关联的 Condition
对象支持 wait/notify
机制。
Lock
对象相对于隐式锁的最大优势是它们可以取消尝试获取锁。如果锁立即不可用或超时(如果指定了超时),tryLock
方法将取消尝试获取锁。如果在获取锁之前另一个线程发送中断信号,lockInterruptibly
方法将取消尝试获取锁。
让我们使用 Lock
对象来解决我们在 活性问题 中看到的死锁问题。阿方斯和加斯东已经训练自己注意到朋友即将鞠躬。我们通过要求我们的 Friend
对象在进行鞠躬之前必须先获取 两个 参与者的锁来模拟这个改进。这里是改进模型的源代码,
。为了展示这种模式的多功能性,我们假设阿方斯和加斯东对于安全鞠躬的新能力如此着迷,以至于他们停不下来彼此鞠躬:Safelock
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.Random; public class Safelock { static class Friend { private final String name; private final Lock lock = new ReentrantLock(); public Friend(String name) { this.name = name; } public String getName() { return this.name; } public boolean impendingBow(Friend bower) { Boolean myLock = false; Boolean yourLock = false; try { myLock = lock.tryLock(); yourLock = bower.lock.tryLock(); } finally { if (! (myLock && yourLock)) { if (myLock) { lock.unlock(); } if (yourLock) { bower.lock.unlock(); } } } return myLock && yourLock; } public void bow(Friend bower) { if (impendingBow(bower)) { try { System.out.format("%s: %s已经向我鞠躬!%n", this.name, bower.getName()); bower.bowBack(this); } finally { lock.unlock(); bower.lock.unlock(); } } else { System.out.format("%s: %s开始向我鞠躬,但发现我已经在鞠躬给他了。%n", this.name, bower.getName()); } } public void bowBack(Friend bower) { System.out.format("%s: %s回鞠躬给我!%n", this.name, bower.getName()); } } static class BowLoop implements Runnable { private Friend bower; private Friend bowee; public BowLoop(Friend bower, Friend bowee) { this.bower = bower; this.bowee = bowee; } public void run() { Random random = new Random(); for (;;) { try { Thread.sleep(random.nextInt(10)); } catch (InterruptedException e) {} bowee.bow(bower); } } } public static void main(String[] args) { final Friend alphonse = new Friend("Alphonse"); final Friend gaston = new Friend("Gaston"); new Thread(new BowLoop(alphonse, gaston)).start(); new Thread(new BowLoop(gaston, alphonse)).start(); } }