写点什么

druid 源码学习九

作者:Nick
  • 2022 年 5 月 20 日
  • 本文字数:2169 字

    阅读完需:约 7 分钟

druid源码学习九

一、引言

昨天我们学习了自旋锁,今天我们通过学习 CreateConnectionThread 线程类继续延伸学习关于锁的知识。

二、锁的延伸

2.1 初探 Condition

在 CreateConnectionThread 线程类中,不仅存在之前学习的 ReentrantLock 锁,还注意到定义的 notEmpty、empty 两个 Condition。进入 Condition 查看其源码会


    protected Condition                                notEmpty;    protected Condition                                empty;
复制代码


发现,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 实现等待/通知:


package service;
import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;
public class MyService { private Lock lock = new ReentrantLock(); public Condition condition = lock.newCondition();
public void await() { try { lock.lock(); System.out.println(" await 时间为" + System.currentTimeMillis()); condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }public void signal() { try { lock.lock(); System.out.println("signal 时间为" + System.currentTimeMillis()); condition.signal(); } finally { lock.unlock(); } }}
复制代码


类 ThreadA.java 代码如下:


import service.MyService;
public class ThreadA extends Thread { private MyService service;
public ThreadA(MyService service) { super(); this.service = service; }
@Override public void run() { service.await( ); }}
复制代码


类 Run.java 代码如下:


package test;
import demo.ThreadA;import service.MyService;import extthread.ThreadA;
public class Run { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); ThreadA a = new ThreadA(service); a.start(); Thread.sleep(3000); service.signal(); }}
复制代码


运行结果:


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 实现等待/通知的。

发布于: 刚刚阅读数: 2
用户头像

Nick

关注

终身学习,向死而生 2020.03.18 加入

得到、极客时间重度学习者,来infoQ 是为了输出倒逼输入

评论

发布
暂无评论
druid源码学习九_Druid_Nick_InfoQ写作社区