多Product多Consumer之間的通訊導致出現程式假死的原因分析
阿新 • • 發佈:2020-09-06
多Product多Consumer之間的通訊導致出現程式假死的原因分析
繼續上篇文章,我們來吧單個生產者消費者改成多個生產者消費者,這裡使用java8的Stream,程式碼如下:
/** * @program: ThreadDemo * @description: 執行緒通訊(生產者-消費者) * @author: [email protected] * @create: 2020-09-06 */ public class ProduceConsumerVersion2 { private int i = 0; private final Object LOCK = new Object(); /** * 是否已經消費 */ private volatile boolean isProduced = false; public void produce() { synchronized (LOCK) { if (isProduced) { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println("P->" + (++i)); LOCK.notify(); isProduced = true; } } } public void consume() { synchronized (LOCK) { if (isProduced) { System.out.println("C->" + i); LOCK.notify(); isProduced = false; } else { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { ProduceConsumerVersion2 pc = new ProduceConsumerVersion2(); // 多個生產者、消費者執行緒執行時,會產生一些問題 Stream.of("P1", "P2").forEach(n -> new Thread(() -> { while (true) { pc.produce(); } }, n).start() ); Stream.of("C1", "C2").forEach(n -> new Thread(() -> { while (true) { pc.consume(); } }, n).start() ); } }
執行效果如下:
可以看到阻塞了,那麼是不是有死鎖了呢,jstack來查一下:
可以看到沒有死鎖,那是為什麼會卡住呢?下面增加一些除錯語句用來定位跟蹤,我把程式碼貼出來,有興趣的朋友在大腦裡分析一下,本地再執行一下驗證自己的想法,程式碼如下:
public class ProduceConsumerVersion2 { private int i = 0; private final Object LOCK = new Object(); /** * 是否已經消費 */ private volatile boolean isProduced = false; public void produce() { synchronized (LOCK) { if (isProduced) { try { System.out.println(Thread.currentThread().getName() + "wait了"); LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { i++; System.out.println(Thread.currentThread().getName() + "生產了->" + i); LOCK.notify(); System.out.println(Thread.currentThread().getName() + "notify了" + i); isProduced = true; } } } public void consume() { synchronized (LOCK) { if (isProduced) { System.out.println(Thread.currentThread().getName() + "消費了->" + i); LOCK.notify(); System.out.println(Thread.currentThread().getName() + "notify了"); isProduced = false; } else { try { System.out.println(Thread.currentThread().getName() + "wait了"); LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { ProduceConsumerVersion2 pc = new ProduceConsumerVersion2(); // 多個生產者、消費者執行緒執行時,會產生一些問題 Stream.of("P1", "P2").forEach(n -> new Thread(() -> { while (true) { pc.produce(); } }, n).start() ); Stream.of("C1", "C2").forEach(n -> new Thread(() -> { while (true) { pc.consume(); } }, n).start() ); } }
執行效果如下:
可以看到P1,C1,P2,C2都wait了,然後程式就假死了,這是什麼原因呢?
這裡我就不一步一步分析了,這裡只需要明白一個道理即可,當有多個wait的時候,notify是隨機的。這個我們後續再探討,先吃個飯~