美文网首页
多线程两个Condition也必须用while判断条件

多线程两个Condition也必须用while判断条件

作者: _Exception | 来源:发表于2019-06-14 17:16 被阅读0次

当时在用ReentrantLock练习生产者消费者,然后获得了两个condition,之前知道多线程条件判断要用while,因为notify不能指定唤醒,这次两个condition不就可以实现指定唤醒吗?就不需要while了吧。于是就用if测试,代码如下。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class TestTranditonalProductorConsumer {

    public static class Basket {
        // 容量
        private int capacity = 2;
        // 当前数量
        private volatile int number = 0;

        private ReentrantLock reentrantLock = new ReentrantLock();
        // 等待get
        private Condition notFull = reentrantLock.newCondition();
        // 等待put
        private Condition notEmpty = reentrantLock.newCondition();

        public Basket put() throws InterruptedException {

            try {
                reentrantLock.lock();
                System.out.println(Thread.currentThread().getName() + "put 线程进入,number为" + number);

                if (number == capacity){
                    System.out.println(Thread.currentThread().getName() + "put 线程开始等待,number为" + number);
                    notEmpty.await();
                    System.out.println(Thread.currentThread().getName() + "put 线程醒过来了,number为" + number);
                }
                number = number + 1;
                notFull.signal();
                System.out.println(Thread.currentThread().getName() + "唤醒get,number为" + number);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }
            return this;
        }

        public Basket get() throws InterruptedException {
            try {
                reentrantLock.lock();
                System.out.println(Thread.currentThread().getName() + "get 线程进入,number为" + number);
                if (number == 0){
                    System.out.println(Thread.currentThread().getName() + "get 线程开始等待,number为" + number);
                    notFull.await();
                    System.out.println(Thread.currentThread().getName() + "get 线程醒过来了,number为" + number);
                }
                number = number - 1;
                notEmpty.signal();
                System.out.println(Thread.currentThread().getName() + "唤醒put,number为" + number);

            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }

            return this;
        }
    }

    public static void main(String[] args) {

        final Basket basket = new Basket();

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    basket.put();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "put线程[" + i + "]").start();
        }

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    basket.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "get线程[" + i + "]").start();
        }
    }
}

日志如下:

put线程[0]put 线程进入,number为0                  
put线程[0]唤醒get,number为1                          --put线程0结束
put线程[4]put 线程进入,number为1
put线程[4]唤醒get,number为2                          --put线程4结束
put线程[1]put 线程进入,number为2
put线程[1]put 线程开始等待,number为2           --put线程1阻塞
put线程[2]put 线程进入,number为2
put线程[2]put 线程开始等待,number为2           --put线程2阻塞
put线程[3]put 线程进入,number为2
put线程[3]put 线程开始等待,number为2           --put线程3阻塞,累计阻塞3个put线程
get线程[0]get 线程进入,number为2
get线程[0]唤醒put,number为1                          --唤醒put 1个,get线程0结束
get线程[2]get 线程进入,number为1
get线程[2]唤醒put,number为0                          --唤醒put 2个,get线程2结束
get线程[3]get 线程进入,number为0
get线程[3]get 线程开始等待,number为0           --get线程3阻塞
put线程[1]put 线程醒过来了,number为0           --put线程1醒过来开始执行,还剩2个put阻塞
put线程[1]唤醒get,number为1                      --put线程1执行结束,并唤醒get线程3(因为只有一个get线程目前阻塞)
get线程[1]get 线程进入,number为1
get线程[1]唤醒put,number为0                    --get线程1结束,唤醒put,还剩1个put阻塞
put线程[2]put 线程醒过来了,number为0          --put线程2醒来执行,并唤醒get线程一个(这里没有可以唤醒的get线程)
put线程[2]唤醒get,number为1                    --put线程2结束
get线程[4]get 线程进入,number为1                    
get线程[4]唤醒put,number为0                    --get线程4结束,唤醒put线程1个
get线程[3]get 线程醒过来了,number为0    --,到这里就是重点了,因为还剩一个就绪的get和一个就绪的put。。。所以问题就在这里。
get线程[3]唤醒put,number为-1
put线程[3]put 线程醒过来了,number为-1
put线程[3]唤醒get,number为0

问题就是倒数4行,无法保证顺序。

相关文章

  • 多线程两个Condition也必须用while判断条件

    当时在用ReentrantLock练习生产者消费者,然后获得了两个condition,之前知道多线程条件判断要用w...

  • Python高级知识点学习(八)

    线程同步 - condition介绍 多线程中的另外一个重要点就是condition:条件变量。condition...

  • JAVA与js知识对比(三)

    js 循环 while do……while for 结构样式: for (初始化;判断条件;改变判断条件){ 执行...

  • kavascript第五章

    循环语句 (1)while(条件){} 例: while(条件){ //满足条件时执行的语句 先判断...

  • js

    循环语句 (1)while(条件){} 例: while(条件){ //满足条件时执行的语句 先判断...

  • JavaScript (5)

    循环语句 (1)while(条件){} 例: while(条件){ //满足条件时执行的语句 先判断...

  • JavaScript⑤数组

    循环语句 (1)while(条件){} 例: while(条件){ //满足条件时执行的语句 先判断...

  • Python——循环、判断

    if判断 语法 if 条件: elif 条件: else: while循环 语法: while 条件: 循环体 e...

  • 4.while

    condition =1while condition <10:print(condition)condition...

  • Shell 循环语句(三) until 循环

    until 循环与 while 循环类似,也同样基于一个条件。但是 until 循环的判断条件正好与 while ...

网友评论

      本文标题:多线程两个Condition也必须用while判断条件

      本文链接:https://www.haomeiwen.com/subject/ewupfctx.html