Java多執行緒之生產者與消費者
阿新 • • 發佈:2020-12-01
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 }