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" 转载请保留原文链接及作者。