1. 程式人生 > 實用技巧 >Java多執行緒之生產者與消費者

Java多執行緒之生產者與消費者

1、倉庫

 1 package com.cn.donleo.thread.house;
 2 
 3 /**
 4  * @author liangd
 5  * date 2020-11-02 10:36
 6  * code 倉庫
 7  */
 8 public class StoreHouse {
 9     /**
10      * 倉庫容納數量
11      */
12     public static int count = 10;
13     /**
14      * 判斷倉庫是否有東西
15      */
16     public static Boolean isNull =false
; 17 public static final Object OBJECT = new Object(); 18 }

2、生產者

 1 package com.cn.donleo.thread.house;
 2 
 3 /**
 4  * @author liangd
 5  * date 2020-11-02 10:40
 6  * code
 7  */
 8 public class Productor extends Thread {
 9     /**
10      * 對於生產者來說,我們需要以下幾個步驟:
11      * 判斷生產者是否還可以生產,因為規定一天只生產10個,可以則繼續,不能則返回
12 * 第一:判斷倉庫裡面是否有還有物品 13 * 第二:如果有,則執行緒等待,即等待消費者來拿 14 * 第三:如果沒有,則生產物品,並提示倉庫裡面有東西,並呼叫消費者 15 * 生產者的run方法,一直向倉庫新增元素 16 */ 17 @Override 18 public void run() { 19 while (true) { 20 //必須要求我們生產者和消費者裡面的東西唯一,否則消費者拿到的東西就不是生產者生產的東西, 21 //所以不能用new WareHouse(),來建立物件
22 synchronized (StoreHouse.OBJECT) { 23 if (StoreHouse.count == 0) { 24 break; 25 } else { 26 if (!StoreHouse.isNull) { 27 System.out.println(getName() + "生產者生產產品"); 28 StoreHouse.isNull = true; 29 /* 30 一、notify和notifyAll的區別 31 主要區別:notify和notifyAll之間的關鍵區別在於notify()只會喚醒一個執行緒, 32 而notifyAll方法將喚醒所有執行緒。 33 34 二、何時在Java中使用notify和notifyAll? 35 1、如果所有執行緒都在等待相同的條件,並且一次只有一個執行緒可以從條件變為true, 36 則可以使用notify over notifyAll。 37 2、在這種情況下,notify是優於notifyAll 因為喚醒所有這些因為我們知道只有一個執行緒會受益 38 而所有其他執行緒將再次等待,所以呼叫notifyAll方法只是浪費CPU。 39 3、雖然這看起來很合理,但仍有一個警告,即無意中的接收者吞下了關鍵通知。 40 通過使用notifyAll,我們確保所有收件人都會收到通知 41 42 */ 43 StoreHouse.OBJECT.notifyAll(); 44 } else { 45 try { 46 /* 47 一、notify、 notifyAll、wait屬於Object裡面的方法 48 二、sleep和wait有什麼區別 49 1、Sleep是屬於Thread類的靜態方法,wait屬於Object的方法。 50 2、最主要是sleep方法沒有釋放鎖,而是放棄CPU的排程。而wait方法釋放了鎖, 51 使得其他執行緒可以進入同步控制塊或者方法。 52 3、wait,notify和notifyAll只能在同步控制方法或者同步控制塊裡面使用, 53 而sleep可以在任何地方使用,synchronized(x){x.notify()//或者wait()} 54 4、sleep必須捕獲異常,wait也需要捕獲異常,notify和notifyAll不需要捕獲異常 55 5、使用wait,notify可以達到執行緒之間的通訊目的 56 */ 57 /* 58 1.使用sleep方法,在毫秒值結束後,執行緒睡醒進入到Runnable/blocked狀態 59 2.使用wait方法,wait方法如果在毫秒值結束後,還沒有被notify喚醒,就會自動醒來, 60 執行緒睡醒進入到Runnable/blocked狀態 61 */ 62 StoreHouse.OBJECT.wait(); 63 // StoreHouse.OBJECT.wait(500); 64 } catch (InterruptedException e) { 65 e.printStackTrace(); 66 } 67 } 68 } 69 } 70 } 71 } 72 }

3、消費者

 1 package com.cn.donleo.thread.house;
 2 
 3 /**
 4  * @author liangd
 5  * date 2020-11-02 10:40
 6  * code
 7  */
 8 public class Consumer extends Thread {
 9     /**
10      * 1.while(true)
11      * 2.synchronized ()
12      * 3.判斷生產者是否已經停止生產了,如果已經停止了,就跳出,如果沒有,則可以繼續去倉庫拿
13      * 4.判斷倉庫是否有物品,如果有,則直接拿。拿了就需要講次數減一,然後呼叫生產者生產
14      * 5.如果沒有,則等待生產者生產
15      */
16     @Override
17     public void run() {
18         while (true) {
19             //必須要求我們生產者和消費者裡面的東西唯一,否則消費者拿到的東西就不是生產者生產的東西,
20             //所以不能用new WareHouse(),來建立物件
21             synchronized (StoreHouse.OBJECT) {
22                 try {
23                     //休眠0.5s
24                     Thread.sleep(500);
25                 } catch (InterruptedException e) {
26                     e.printStackTrace();
27                 }
28                 if (StoreHouse.count == 0) {
29                     break;
30                 } else {
31                     if (StoreHouse.isNull) {
32                         System.out.println(getName() + "消費者可以拿產品了");
33                         StoreHouse.isNull = false;
34                         StoreHouse.OBJECT.notifyAll();
35                         StoreHouse.count--;
36                     } else {
37                         try {
38                             StoreHouse.OBJECT.wait();
39                         } catch (InterruptedException e) {
40                             e.printStackTrace();
41                         }
42                     }
43                 }
44             }
45         }
46     }
47 }

4、測試類

 1 package com.cn.donleo.thread.house;
 2 
 3 /**
 4  * @author liangd
 5  * date 2020-11-02 10:56
 6  * code 生產者消費者測試類
 7  */
 8 public class TestProductorCunsumer {
 9     public static void main(String[] args){
10         //執行緒1
11         Productor productor = new Productor();
12         productor.setName("生產者");
13         //執行緒2
14         Consumer consumer1 = new Consumer();
15         consumer1.setName("A消費者");
16         //執行緒3
17         Consumer consumer2 = new Consumer();
18         consumer2.setName("B消費者");
19         productor.start();
20         consumer1.start();
21         consumer2.start();
22     }
23 }