druid 源码学习九
一、引言
昨天我们学习了自旋锁,今天我们通过学习 CreateConnectionThread 线程类继续延伸学习关于锁的知识。
二、锁的延伸
2.1 初探 Condition
在 CreateConnectionThread 线程类中,不仅存在之前学习的 ReentrantLock 锁,还注意到定义的 notEmpty、empty 两个 Condition。进入 Condition 查看其源码会
发现,Condition 是一个接口,并且在 java.util.concurrent.locks 下。查找 jdk api 并展开并且在 java.util.concurrent.locks 包:
打开 Condition 接口 API:
Condition 因素出 Object 监视器方法( wait , notify 和 notifyAll )成不同的对象,以得到具有多个等待集的每个对象,通过将它们与使用任意的组合的效果 Lock 个实现。 Lock 替换 synchronized 方法和语句的使用, Condition 取代了对象监视器方法的使用。
条件(也称为条件队列或条件变量 )为一个线程暂停执行(“等待”)提供了一种方法,直到另一个线程通知某些状态现在可能为真。 因为访问此共享状态信息发生在不同的线程中,所以它必须被保护,因此某种形式的锁与该条件相关联。 等待条件的关键属性是它原子地释放相关的锁并挂起当前线程,就像 Object.wait 。
一个 Condition 实例本质上绑定到一个锁。 要获得特定 Condition 实例的 Condition 实例,请使用其 newCondition()方法。
理解起来比较费劲,查阅《Java 多线程核心技术》找到这段:
关键字 synchronized 与 wait()和 notify()/notifyAll()方法相结合可以实现等待/通知模式,类 ReentrantLock 也可以实现同样的功能,但需要借助于 Condition 对象。Condition 类是在 JDK5 中出现的技术,使用它有更好的灵活性,比如可以实现多路通知功能,也就是在一个 Lock 对象里面可以创建多个 Condition(即对象监视器)实例,线程对象可以注册在指定的 Condition 中,从而可以有选择性地进行线程通知,在调度线程上更加灵活。
通过上述描述,我们可以至少得出一下 2 个结论:
1 Condition 类是在 JDK5 中出现的技术;
2 Condition 使用更具灵活性,可实现多路通知功能;
3 在一个 Lock 对象里可以创建多个 Condition 实例。
2.2 Condition 的应用
接下来我们看看 Condition 如何使用;
在使用 notify()/notifyAll()方法进行通知时,被通知的线程却是由 JVM 随机选择的。但使用 ReentrantLock 结合 Condition 类是可以实现前面介绍过的“选择性通知”,这个功能是非常重要的,而且在 Condition 类中是默认提供的。
而 synchronized 就相当于整个 Lock 对象中只有一个单一的 Condition 对象,所有的线程都注册在它一个对象的身上。线程开始 notifyAll()时,需要通知所有的 WAITING 线程,没有选择权,会出现相当大的效率问题。
接下来我们看一下如何正确的使用 Condition 实现等待/通知:
类 ThreadA.java 代码如下:
类 Run.java 代码如下:
运行结果:
await 时间为:14145486209593
signal 时间为:14145486203953
成功实现等待/通知模式。Object 类中的 wait()方法相当于 Condition 类中的 await()方法。Object 类中的 wait(long timeout)方法相当于 Condition 类中的 await(long time,TimeUnit unit)方法。Object 类中的 notify()方法相当于 Condition 类中的 signal()方法。Object 类中的 notifyAll()方法相当于 Condition 类中的 signalAll()方法
三、总结
本篇,我们继续延伸学习了锁的知识,对 Condition 进行深入学习,如何通过 Condition 实现等待/通知的。
版权声明: 本文为 InfoQ 作者【Nick】的原创文章。
原文链接:【http://xie.infoq.cn/article/da9b78e481cd5323b9a42e387】。文章转载请联系作者。
评论