Java 多线程系列 8:JDK 中的管程实现之条件变量
管程包括锁和条件变量,他们组合在一起解决了多线程互斥和协同的问题。上篇文章介绍了 JDK 包中的 Lock 接口以及主要的加锁方法,这篇文章介绍如何使用条件变量来解决多个线程协同的问题。和 Java 语言提供的由 synchronized/wait/nofity/notifyAll 组合实现的管程相比,JDK 包中实现的管程条件变量更加灵活和强大。
JDK 包的 Lock 接口有一个方法:newCondition(),这个方法返回一个条件变量(Condition)对象。与 synchronized 只能拥有一个条件变量相比,Lock 对象可以拥有多个条件变量,以实现复杂的状态控制。例如在生产者和消费者模式中,可以用两个条件变量(Full 和 Empty)来实现生产者和消费者之间的协同,具体做法就是通过 Condition 提供的 await/signal/signalAll 来实现。
Condition 提供的 await/signal/signalAll 和 Object 提供的 wait/notify/nofityAll 实现的功能是一样的,但千万不要用错。如果你用的是 JDK 包的 Lock,就不能调用 wait/nofity/nofityAll。
下面我们来看一个简单的例子:
这个例子演示了如何基于条件变量来在两个线程间进行协同。主线程尝试获取一个值,获取不到则进入的等待。未来某个时候有别的线程来设置这个值,然后通知主线程,主线程于是被唤醒拿到结果。还有一个小细节,在通知主线程时,用了 condiation.signalAll()方法,记住:任何时候用 signalAll()方法总不会错,避免出现线程饥饿的情况。
同样的,我们也可以用类似的方式来实现生产者-消费者模式,当然你需要两个条件变量。具体这里就不给代码了,大家可以自行尝试一下。
上面的示例代码实际上是实现 Future 和线程池的一种思路,不过幸运的是,JDK 并发包中早就实现了功能非常强大的 Future 和 ThreadPoolExecutor,后继我们将继续介绍它们的用法和设计思路。
版权声明: 本文为 InfoQ 作者【BigBang!】的原创文章。
原文链接:【http://xie.infoq.cn/article/39305e6900738571453fbf5c1】。文章转载请联系作者。
评论