并发编程之 wait()为什么要处于while循环中?

我们不妨来看一下情景:

队列中被添加了一个元素,A,B线程被notifyAll()唤醒,可以取元素.

我们来从代码分析:

  若用if:

1 synchronized (monitor) {
2     //  判断条件谓词是否得到满足
3     if(queue.IsEmpty()) {
4         //  等待唤醒
5         monitor.wait(); // 第五行等待状态
6     }
7     //  处理业务逻辑:从队列中取出元素
        queue.get();
    }

则执行流程为:

线程A取出最后一个元素> A释放锁 -> B得到锁 -> B从第五行向下执行 -> B从队列中取出元素 -> 越界异常

值得注意的是,因为wait住在第五行那么A线程执行完后,B线程也被唤醒,并且从第五行向下执行,于是就执行get()方法,发生越界异常.


若用while:

1 synchronized (monitor) {
2     //  判断条件谓词是否得到满足
3     while(queue.IsEmpty()) {
4         //  等待唤醒
5         monitor.wait(); //第五行等待状态
6     }
7     //  处理业务逻辑:从队列中取出元素
    }

则执行流程为:

 线程A取出最后一个元素> A释放锁 -> B得到锁 -> B从第五行向下执行 -> 又进行while循环 -> 发现队列为空 -> 继续等待

值得注意的是,这里用了while后,虽然也从第五行开始向下执行,但是并不会退出while循环,而是继续进行while判断, 也就不会发生越界异常了.


我们来总结一下:

                   wait()方法之所以要用while而不是if是因为 :

当多个线程并发访问同一个资源的时候, 若消费者同时被唤醒,但是只有一个资源可用, 那么if会导致资源被用完后直接去获取资源(发生越界异常等),而while则会让每个消费者获取之前再去判断一下资源是否可用.可用则获取,不可用则继续wait住.

原创文章 63 获赞 48 访问量 8万+

猜你喜欢

转载自blog.csdn.net/csp_6666/article/details/103547048