JUC中的线程通信 Condition

Posted XeonYu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC中的线程通信 Condition相关的知识,希望对你有一定的参考价值。

上一篇:

JUC中的 ReentrantLock

上一篇文章我们简单用了下ReentrantLock。
我们知道,用synchronized的时候,我们可以通过Object类中的wait和notify来实现线程间的通信。但是wait和notify只能在synchronized中使用,那使用Lock时如何实现线程通信呢?

Condition

Condition是一个接口,他就是替代Object中的wait和notify方法来解决使用Lock时线程间的通信问题。

Condition要比Object中的wait和notify更加灵活一些,且能实现更加复杂的业务。

我们先来简单用一用Condition

有一下代码:

class MyNumber {
    private final ReentrantLock lock = new ReentrantLock();


    /*条件*/
    private final Condition condition = lock.newCondition();


    /*默认值为0*/
    private int number = 0;


    /*加操作*/
    public void add() {
        lock.lock();
        try {
            String name = Thread.currentThread().getName();

            while (number == 1) {
                /*当值为不为0时  等待其他线程将值变为变为0*/
                condition.await();
            }

            /*值为0时  加一*/
            number++;
            System.out.println(name + "加一:" + number);
            /*通知其他个线程可以做减一操作了*/
            condition.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }

        }
    }


    public void reduce() {
        lock.lock();
        String name = Thread.currentThread().getName();

        try {
            /*值为0时  等待*/
            while (number == 0) {
                condition.await();
            }

            /*不为0时  减一*/
            number--;
            System.out.println(name + "减一:" + number);

            /*通知其他线程可以做加一操作了*/
            condition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }

        }


    }


}

这个Number类有两个方法,加一和减一。
main方法如下:

    public static void main(String[] args) {

        MyNumber number = new MyNumber();

        new Thread(() -> {

            for (int i = 0; i < 5; i++) {
                number.add();
            }

        }, "线程1").start();
        new Thread(() -> {

            for (int i = 0; i < 5; i++) {
                number.reduce();
            }

        }, "线程2").start();


    }

运行一下:

可以看到,符合预期,线程之间的通信是没有问题的。

再加2个线程试一下:

    public static void main(String[] args) {

        MyNumber number = new MyNumber();

        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                number.add();
            }
        }, "线程1").start();
        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                number.reduce();
            }
        }, "线程2").start();
        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                number.add();
            }
        }, "线程3").start();
        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                number.reduce();
            }
        }, "线程4").start();


    }

运行来看一下:

发现运行结果没有走完,且卡死了。
原因是signal跟notify一样,当有多个线程都处于等待中,只会唤醒其中一个,另一个就一直处于等待中,最终就会出现四个线程都在等待被唤醒,造成死锁

所以,如果有多个线程时,一定要全部唤醒,以免出现死锁。

signal改为 signalAll 即可

改好后再来运行一下:

可以看到,这下运行就正常了。

Condition暂时就是这些。


如果你觉得本文对你有帮助,麻烦动动手指顶一下,可以帮助到更多的开发者,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!

以上是关于JUC中的线程通信 Condition的主要内容,如果未能解决你的问题,请参考以下文章

JUC中的线程通信 Condition

JUC-Condition线程通信

Java中juc并发包下的Condition接口与ReentrantLock对象锁实现线程通信

JUC---06线程间通信

JUC---06线程间通信

多线程编程-- part 5.2 JUC锁之Condition条件