JUC并发系列(二):详解使用Condition替代wait、notify【实现精准通知唤醒】

跑起一个程序,并不难;难的是,能让程序跑多远!—— 一颗剽悍的种子

在这里插入图片描述
JUC并发系列

初识JUC并发系列(一):什么?听说你搞混了并发和并行

一、什么是Condition

jdk1.5的时候更新了Condition,可以用来替代原先的 waitnotify 实现线程间协作,因为Condition的 awaitsignal 方式实现线程协作更安全且高效。

可以看之前深入多线程系列,我们使用管程方式和信号灯方式解决生产者与消费者问题就是用 waitnotify 实现。

深入多线程十五:管程方式解决生产者与消费者问题

深入多线程十六:信号灯方式解决生产者与消费者问题

二.手敲代码实现Condition实现精准通知唤醒

有一个场景,我们想要的一个输出结果是按照ABC的顺序执行,那么我们就用今天的主角 Condition 实现。

2.1没有使用Condition

在实现Condition精确通知唤醒前,先看没有使用Condition输出结果的代码段。(对比着学习更为直观)

public class demo{
    
    
    public static void main(String[] args) {
    
    
        Data data = new Data();
       new Thread(()->{
    
    
           for (int i = 0; i < 5; i++) {
    
    
               data.testA();
           }
       },"一颗剽悍的种子A").start();
       new Thread(()->{
    
    
           for (int i = 0; i < 5; i++) {
    
    
               data.testB();
           }
       },"一颗剽悍的种子B").start();
       new Thread(()->{
    
    
           for (int i = 0; i < 5; i++) {
    
    
               data.testC();
           }
       },"一颗剽悍的种子C").start();
    }
}
class Data{
    
    
    public void testA(){
    
    
        System.out.println(Thread.currentThread().getName() + "A");
    }
    public void testB(){
    
    
        System.out.println(Thread.currentThread().getName() + "B");
    }
    public void testC(){
    
    
        System.out.println(Thread.currentThread().getName() + "C");
    }
}

运行结果

可以看到顺序乱了,并不是按照我们想要的执行顺序。

扫描二维码关注公众号,回复: 11827994 查看本文章

在这里插入图片描述

2.2使用Condition实现精准通知唤醒

synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock同样是独占锁,但加锁和解锁的过程需要手动进行,不易操作,但非常灵活。

关键代码

手动锁 ->判断 ->执行 ->通知 ->手动关锁

    public void testA(){
    
    
        lock.lock();
        try {
    
    
        while (num != 1){
    
    
                conditionA.await(); //等待
            }
            System.out.println(Thread.currentThread().getName() + "A");
            num++;
            conditionB.signal();    //通知
        }catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            lock.unlock();
        }
    }

全部代码

public class demo{
    
    
    public static void main(String[] args) {
    
    
        Data data = new Data();
       new Thread(()->{
    
    
           for (Integer i = 0; i < 5; i++) {
    
    
               data.testA();
           }
       },"一颗剽悍的种子A").start();
       new Thread(()->{
    
    
           for (Integer i = 0; i < 5; i++) {
    
    
               data.testB();
           }
       },"一颗剽悍的种子B").start();
       new Thread(()->{
    
    
           for (Integer i = 0; i < 5; i++) {
    
    
               data.testC();
           }
       },"一颗剽悍的种子C").start();
    }
}
class Data{
    
    
    private Lock lock = new ReentrantLock();
    private Condition conditionA = lock.newCondition();
    private Condition conditionB = lock.newCondition();
    private Condition conditionC = lock.newCondition();
    private Integer num = 1;    //1 = A  2 = B 3 = C

    public void testA(){
    
    
        lock.lock();
        try {
    
    
        while (num != 1){
    
    
                conditionA.await(); //等待
            }
            System.out.println(Thread.currentThread().getName() + "A");
            num++;
            conditionB.signal();    //通知
        }catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            lock.unlock();
        }
    }
    public void testB(){
    
    
        lock.lock();
        try {
    
    
            while (num != 2){
    
    
                conditionB.await(); //等待
            }
            System.out.println(Thread.currentThread().getName() + "B");
            num++;
            conditionC.signal();    //通知
        }catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            lock.unlock();
        }
    }
    public void testC(){
    
    
        lock.lock();
        try {
    
    
            while (num != 3){
    
    
                conditionC.await(); //等待
            }
            System.out.println(Thread.currentThread().getName() + "C");
            num = 1;
            conditionA.signal();    //通知
        }catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            lock.unlock();
        }
    }
}

运行结果
在这里插入图片描述

三、防止虚假唤醒

看过之前的深入多线程系列或上面的代码的小伙伴,如果留心会发现在判断中我们更多的是使用 while 判断,而不是 if,因为 if 可能出现虚假唤醒。

那何为防止虚假唤醒?

所谓虚假唤醒就是线程虽然可以唤醒,但不会被通知,中断或超时。

四、最后

最后的最后,为了更好的阅读体验,我把想说的话都放在了下面,嘿嘿。

我是一颗剽悍的种子 把我会的,认真的分享 是我写博客一直不变的信条。
如果你能看到这篇博文,说明咱们还是很有缘的;希望能带给你一些许帮助,创作的不易,
把我文章的知识带走,你的三连留下,点赞,评论,关注,是我最大的动力。

猜你喜欢

转载自blog.csdn.net/A_hxy/article/details/108665139
今日推荐