概述
高并发编程-线程通信_使用wait和notify进行线程间的通信2_多生产者多消费者导致程序假死原因分析 中分析了假死的原因,这里我们来看下改如何解决在多线程下出现的这个问题呢?
解决办法
- 多线程情况用while而不是if 来判断条件是否满足
- notify —> notifyAll
package com.artisan.test; import java.util.stream.Stream; public class MultiProduceConsumerDemo2 { // 对象监视器-锁 private final Object LOCK = new Object(); // 是否生产出数据的标识 private boolean isProduced = false; // volatile 确保可见性, 假设 i 就是生产者生产的数据 private volatile int i = 0; public void produce() { synchronized (LOCK) { String msg = isProduced ? "已生产货物" : "没有货物可搬运"; // while 每次被唤醒时都会先检查isProduced是否滿足條件再继续 // 不能用if的原因:if它将不再判断isProduced是否滿足條件,直接继续,引发错误 // 举个例子 t1 ,t2 都进入到了wait ,然后使用if, 唤醒了t2后,不再判断isProduced是否滿足條件 // 直接又生产了一个,导致生产多了数据 while (isProduced) { try { System.out.println(Thread.currentThread().getName() + " GOT LOCK ,isProduced= " + isProduced + " wait becauseof " + msg); LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } i++; System.out.println(Thread.currentThread().getName() + " GOT LOCK ,isProduced= " + isProduced + " Produce:" + i); // 唤醒所有正在等待这个对象的monitor的线程 LOCK.notifyAll(); isProduced = true; } } public void consume() { // 加锁 synchronized (LOCK) { String msg = isProduced ? "已生产货物" : "没有货物可搬运"; // while 每次被唤醒时都会先检查isProduced是否滿足條件再继续 while (!isProduced) { try { System.out.println(Thread.currentThread().getName() + " wait becauseof " + msg); LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + " GOT LOCK ,isProduced= " + isProduced + " Consume:" + i); //唤醒所有正在等待这个对象的monitor的线程 LOCK.notifyAll(); isProduced = false; } } public static void main(String[] args) { MultiProduceConsumerDemo2 produceConsumerDemo = new MultiProduceConsumerDemo2(); Stream.of("P1", "P2").forEach(n -> new Thread(n) { @Override public void run() { while (true) produceConsumerDemo.produce(); } }.start()); Stream.of("C1", "C2").forEach(n -> new Thread(n) { @Override public void run() { while (true) produceConsumerDemo.consume(); } }.start()); } }