126-多线程下的生产者消费者模型,以及详细介绍notifyAll方法
public final void wait()方法
使当前线程等待,直到另一个线程为此对象调用
notify()方法或notifyAll()方法。此方法的行为就像完全执行调用wait(0)一样。当前线程必须拥有该对象的监视器。线程释放此监视器的所有权,并等待直到另一个线程通过调用notify方法或notifyAll方法通知等待在此对象监视器上等待的线程唤醒。然后,线程等待,直到它可以重新获得监视器的所有权并恢复执行(即可运行状态)。
public final void notify()方法
唤醒正在此对象的监视器上等待的单个线程。如果有任何线程在此对象上等待,则选择其中一个唤醒。选择是任意的,并且可以根据实现情况进行选择。线程通过调用其中一个wait方法在对象的监视器上等待。
public final void notifyAll()方法
唤醒正在此对象的监视器上等待的所有线程。线程通过调用其中一个wait方法在对象的监视器上等待。
改造多线程下的生产者-消费者模型:
public void produce() {
    synchronized (LOCK) {
        // 分析此处为什么使用while,而不是用if?
        while (isProduced) {
            LOCK.wait();
        }
        System.out.println(Thread.currentThread().getName() + "->" + (++i));
        LOCK.notifyAll();
        isProduced = true;
    }
}public void consume() {
    synchronized (LOCK) {
        while (!isProduced) {
            LOCK.wait();
        }
        System.out.println(Thread.currentThread().getName() + "->" + i);
        LOCK.notifyAll();
        isProduced = false;
    }
}public static void main(String[] args) {
    ProduceConsumerVersion3 pc = new ProduceConsumerVersion3();
    Stream.of("P1", "P2", "P3").forEach(n -> new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                pc.produce();
                Thread.sleep(10);
            }
        }
    }, n).start());
    Stream.of("C1", "C2", "C3", "C4").forEach(n -> new Thread(() -> {
        while (true) {
            pc.consume();
            Thread.sleep(10);
        }
    }, n).start());
}分析此处为什么使用while,而不是用if?
while (isProduced) {
    LOCK.wait();
}notifyAll()方法将会唤醒所有的生产者线程。
如果使用if():线程A先抢到锁,运行时判断有没有生产数据,无则生产数据并运行完成,当它再次抢锁运行时发现已经生产过数据则会进行wait()操作;线程B抢到锁运行时将会跳过判断直接生产数据,从而造成了消费者还没有消费完数据又重复生产。
例:生产两次消费一次,生产一次消费两次
P2->2
P3->3
C3->3
P1->4
C4->4
C2->4转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 tuyrk@qq.com
文章标题:126-多线程下的生产者消费者模型,以及详细介绍notifyAll方法
文章字数:606
本文作者:神秘的小岛岛
发布时间:2019-11-30, 17:33:41
最后更新:2019-12-01, 16:10:35
原始链接:https://www.tuyrk.cn/wang-thread/126-multi-thread-notifyall/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。
 
            