多線程學習-基礎(十二)生產者消費者模型:wait(),sleep(),notify()實現
一、多線程模型一:生產者消費者模型
(1)模型圖:(從網上找的圖,清晰明了)
(2)生產者消費者模型原理說明:
這個模型核心是圍繞著一個“倉庫”的概念,生產者消費者都是圍繞著:“倉庫”來進行操作,一個倉庫同時只能被一個生產者線程或一個消費者線程所操作,synchronized鎖住的也是這個倉庫,倉庫是一個容器,所以會有邊界值,0和倉庫可存放上限,在這個上限內,可以設置多種級別,不同的級別可以執行不同的策略流程。
(3)本案例使用知識點:
Thread.currentThread().interrupt();//中斷線程
this.notify();//喚醒其他線程
this.wait();//停止出貨
Thread.sleep(1000);//放置一個線程占用cpu過久
這些知識點都是多線程的基礎知識點,以後會嘗試使用:BlockingQueue,線程池來擴展這些簡單的案例,個人覺得,先掌握好簡單的使用,然後再在其上擴展,記憶會比較深刻一點。
二、案例源碼
案例說明:
本案例有:產品類Product ,倉庫類Warehouse , 生產者線程(實現Runnable)Producer , 消費者線程(實現Runnable)Consumer ,以及一個啟動類ThreadStart
好了,直接貼出代碼吧。
產品類Product
1 packagecom.jason.proCusModels; 2 /** 3 * 產品類 4 * @function 5 * @author 小風微涼 6 * @time 2018-4-26 下午8:00:40 7 */ 8 public class Product { 9 //產品名稱 10 private String pName; 11 //產品編號 12 private String proNo; 13 public Product(String pName,String proNo){ 14 this.pName=pName; 15this.proNo=proNo; 16 } 17 //設置getter方法 18 public String getpName() { 19 return pName; 20 } 21 public String getProNo() { 22 return proNo; 23 } 24 //重寫toString方法 25 @Override 26 public String toString() { 27 return "產品名稱:"+this.pName+",產品編號:"+this.proNo; 28 } 29 }
倉庫類Warehouse
1 package com.jason.proCusModels; 2 import java.util.ArrayList; 3 import java.util.List; 4 /** 5 * 倉庫類 6 * @function 7 * @author 小風微涼 8 * @time 2018-4-26 下午7:59:34 9 */ 10 public class Warehouse { 11 //倉庫名稱 12 private String name; 13 //倉庫最大容量上限 14 private int MAX_COUNT=100; 15 //設置倉庫貨物預警下限:此處可以加設進貨策略,不同的缺貨程度,設置不同的進貨速度(以後再補充) 16 private int MIN_COUNT=20; 17 //倉庫存放商品的容器 18 public static List<Product> proList; 19 //靜態塊 20 static{ 21 proList=new ArrayList<Product>(); 22 } 23 //構造器 24 public Warehouse(String name){ 25 this.name=name; 26 } 27 /** 28 * 倉庫進貨 29 * @param count 進貨數量 30 */ 31 public synchronized void Purchase(int count){ 32 //判斷當前貨物+count是否超過上限 如果超過,則停止進貨 只允許出貨 33 int currCount=proList.size(); 34 if(currCount+count>MAX_COUNT){ 35 this.notify();//喚醒其他線程 36 try { 37 System.out.println(Thread.currentThread().getName()+"準備進貨:"+count+"個產品,當前倉庫貨物有:"+currCount+"個,【貨物超過倉庫存放上限:"+MAX_COUNT+"】,已經停止進貨"); 38 this.wait();//停止進貨 39 } catch (InterruptedException e) { 40 e.printStackTrace(); 41 Thread.currentThread().interrupt();//中斷線程 42 } 43 }else{//判斷:當前貨物+count沒有超過上限 則可以繼續進貨 44 if(currCount<=MIN_COUNT){ 45 System.out.println("當前倉庫剩余貨物數量,在最低警戒線一下,請抓緊時間補貨!!!!!!!"); 46 } 47 //開始進貨 48 for(int i=0;i<count;i++){ 49 //拿到產品 50 Product prod=new Product("IphoneX", "*");//編號隨意,暫時不會用到 51 //入庫 52 proList.add(prod); 53 } 54 System.out.println(Thread.currentThread().getName()+"準備進貨:"+count+"個產品,當前倉庫貨物有:"+currCount+"個,進貨後倉庫總有:"+proList.size()); 55 } 56 try { 57 Thread.sleep(1000);//放置一個線程占用cpu過久 58 } catch (InterruptedException e) { 59 e.printStackTrace(); 60 } 61 } 62 /** 63 * 倉庫出貨 64 * @param count·出貨數量 65 */ 66 public synchronized void Shipments(int count){ 67 //如果當前倉庫貨物余貨為0 或者出貨數量<count 則停止出貨 開始進貨 68 int currCount=proList.size(); 69 if(currCount==0 || currCount<count){ 70 this.notify();//喚醒其他線程 71 try { 72 System.out.println(Thread.currentThread().getName()+"準備出貨:"+count+"個產品,當前倉庫貨物有:"+currCount+"個,【貨物短缺,請盡快進貨】,已經停止出貨"); 73 this.wait();//停止出貨 74 } catch (InterruptedException e) { 75 e.printStackTrace(); 76 Thread.currentThread().interrupt();//中斷線程 77 } 78 }else{//倉庫貨物充足,可繼續出貨 79 //出貨 80 proList=proList.subList(count, proList.size()); 81 System.out.println(Thread.currentThread().getName()+"準備出貨:"+count+"個產品,當前倉庫貨物有:"+currCount+"個,出貨後倉庫總有:"+proList.size()); 82 } 83 try { 84 Thread.sleep(1000);//放置一個線程占用cpu過久 85 } catch (InterruptedException e) { 86 e.printStackTrace(); 87 } 88 } 89 /** 90 * 拿到倉庫容器 91 * @return 92 */ 93 public static List<Product> getProList() { 94 return proList; 95 } 96 }
生產者線程(實現Runnable)Producer
1 package com.jason.proCusModels; 2 /** 3 * 生產者類(線程) 4 * @function 5 * @author 小風微涼 6 * @time 2018-4-26 下午7:57:47 7 */ 8 public class Producer implements Runnable{ 9 //生產者名稱 10 private String name; 11 //倉庫對象 12 private Warehouse whose;//這樣寫只是為了讓關系更加清晰 實際倉庫容器:Warehouse.proList 13 //消費產品數量 14 private int threadCount; 15 //構造器 16 public Producer(String name,int threadCount,Warehouse whose){ 17 this.name=name; 18 this.whose=whose; 19 this.threadCount=threadCount; 20 } 21 public void run() { 22 Thread.currentThread().setName(this.name); 23 //開始進貨 24 while(true){ 25 whose.Purchase(threadCount); 26 } 27 } 28 }
消費者線程(實現Runnable)Consumer
1 package com.jason.proCusModels; 2 /** 3 * 消費者類(線程) 4 * @function 5 * @author 小風微涼 6 * @time 2018-4-26 下午7:58:59 7 */ 8 public class Consumer implements Runnable{ 9 //消費者名稱 10 private String name; 11 //倉庫對象 12 private Warehouse whose;//這樣寫只是為了讓關系更加清晰 實際倉庫容器:Warehouse.proList 13 //消費產品數量 14 private int threadCount; 15 //構造器 16 public Consumer(String name,int threadCount,Warehouse whose){ 17 this.name=name; 18 this.whose=whose; 19 this.threadCount=threadCount; 20 } 21 public void run() { 22 Thread.currentThread().setName(this.name); 23 //開始出貨 24 while(true){ 25 whose.Shipments(threadCount); 26 } 27 } 28 }
一個啟動類ThreadStart
1 package com.jason.proCusModels; 2 /** 3 * 多線程學習 4 * @function 生產者消費者模型啟動類 5 * @author 小風微涼 6 * @time 2018-4-26 下午8:51:56 7 */ 8 public class ThreadStart { 9 /** 10 * 啟動項 11 * @param args 12 */ 13 public static void main(String[] args) { 14 //創建一個倉庫 15 Warehouse whose=new Warehouse("1號倉庫"); 16 //創建10個生產者線程 17 for(int i=1;i<=10;i++){ 18 new Thread(new Producer(i+"號生產者",(int)(Math.random()*10+1),whose)).start(); 19 } 20 //創建15個消費者線程 21 for(int i=1;i<=15;i++){ 22 new Thread(new Consumer(i+"號消費者",(int)(Math.random()*10+1),whose)).start(); 23 } 24 } 25 }
運行結果:(僅截取部分結果)
當前倉庫剩余貨物數量,在最低警戒線一下,請抓緊時間補貨!!!!!!! 1號生產者準備進貨:6個產品,當前倉庫貨物有:0個,進貨後倉庫總有:6 12號消費者準備出貨:1個產品,當前倉庫貨物有:6個,出貨後倉庫總有:5 15號消費者準備出貨:3個產品,當前倉庫貨物有:5個,出貨後倉庫總有:2 14號消費者準備出貨:3個產品,當前倉庫貨物有:2個,【貨物短缺,請盡快進貨】,已經停止出貨 11號消費者準備出貨:9個產品,當前倉庫貨物有:2個,【貨物短缺,請盡快進貨】,已經停止出貨 13號消費者準備出貨:2個產品,當前倉庫貨物有:2個,出貨後倉庫總有:0 10號消費者準備出貨:6個產品,當前倉庫貨物有:0個,【貨物短缺,請盡快進貨】,已經停止出貨 4號消費者準備出貨:1個產品,當前倉庫貨物有:0個,【貨物短缺,請盡快進貨】,已經停止出貨 6號消費者準備出貨:2個產品,當前倉庫貨物有:0個,【貨物短缺,請盡快進貨】,已經停止出貨 9號消費者準備出貨:2個產品,當前倉庫貨物有:0個,【貨物短缺,請盡快進貨】,已經停止出貨 8號消費者準備出貨:9個產品,當前倉庫貨物有:0個,【貨物短缺,請盡快進貨】,已經停止出貨 5號消費者準備出貨:5個產品,當前倉庫貨物有:0個,【貨物短缺,請盡快進貨】,已經停止出貨 7號消費者準備出貨:5個產品,當前倉庫貨物有:0個,【貨物短缺,請盡快進貨】,已經停止出貨 3號消費者準備出貨:4個產品,當前倉庫貨物有:0個,【貨物短缺,請盡快進貨】,已經停止出貨 2號消費者準備出貨:3個產品,當前倉庫貨物有:0個,【貨物短缺,請盡快進貨】,已經停止出貨 1號消費者準備出貨:5個產品,當前倉庫貨物有:0個,【貨物短缺,請盡快進貨】,已經停止出貨 當前倉庫剩余貨物數量,在最低警戒線一下,請抓緊時間補貨!!!!!!! 10號生產者準備進貨:1個產品,當前倉庫貨物有:0個,進貨後倉庫總有:1 當前倉庫剩余貨物數量,在最低警戒線一下,請抓緊時間補貨!!!!!!! 9號生產者準備進貨:3個產品,當前倉庫貨物有:1個,進貨後倉庫總有:4 當前倉庫剩余貨物數量,在最低警戒線一下,請抓緊時間補貨!!!!!!! 8號生產者準備進貨:5個產品,當前倉庫貨物有:4個,進貨後倉庫總有:9 當前倉庫剩余貨物數量,在最低警戒線一下,請抓緊時間補貨!!!!!!! 8號生產者準備進貨:5個產品,當前倉庫貨物有:9個,進貨後倉庫總有:14 當前倉庫剩余貨物數量,在最低警戒線一下,請抓緊時間補貨!!!!!!! 7號生產者準備進貨:9個產品,當前倉庫貨物有:14個,進貨後倉庫總有:23 6號生產者準備進貨:9個產品,當前倉庫貨物有:23個,進貨後倉庫總有:32 5號生產者準備進貨:1個產品,當前倉庫貨物有:32個,進貨後倉庫總有:33 4號生產者準備進貨:8個產品,當前倉庫貨物有:33個,進貨後倉庫總有:41 3號生產者準備進貨:9個產品,當前倉庫貨物有:41個,進貨後倉庫總有:50 2號生產者準備進貨:8個產品,當前倉庫貨物有:50個,進貨後倉庫總有:58 3號生產者準備進貨:9個產品,當前倉庫貨物有:58個,進貨後倉庫總有:67 4號生產者準備進貨:8個產品,當前倉庫貨物有:67個,進貨後倉庫總有:75 5號生產者準備進貨:1個產品,當前倉庫貨物有:75個,進貨後倉庫總有:76 6號生產者準備進貨:9個產品,當前倉庫貨物有:76個,進貨後倉庫總有:85 6號生產者準備進貨:9個產品,當前倉庫貨物有:85個,進貨後倉庫總有:94 6號生產者準備進貨:9個產品,當前倉庫貨物有:94個,【貨物超過倉庫存放上限:100】,已經停止進貨 7號生產者準備進貨:9個產品,當前倉庫貨物有:94個,【貨物超過倉庫存放上限:100】,已經停止進貨 8號生產者準備進貨:5個產品,當前倉庫貨物有:94個,進貨後倉庫總有:99 9號生產者準備進貨:3個產品,當前倉庫貨物有:99個,【貨物超過倉庫存放上限:100】,已經停止進貨 10號生產者準備進貨:1個產品,當前倉庫貨物有:99個,進貨後倉庫總有:100 2號消費者準備出貨:3個產品,當前倉庫貨物有:100個,出貨後倉庫總有:97 2號消費者準備出貨:3個產品,當前倉庫貨物有:97個,出貨後倉庫總有:94 3號消費者準備出貨:4個產品,當前倉庫貨物有:94個,出貨後倉庫總有:90 3號消費者準備出貨:4個產品,當前倉庫貨物有:90個,出貨後倉庫總有:86 3號消費者準備出貨:4個產品,當前倉庫貨物有:86個,出貨後倉庫總有:82 3號消費者準備出貨:4個產品,當前倉庫貨物有:82個,出貨後倉庫總有:78 5號消費者準備出貨:5個產品,當前倉庫貨物有:78個,出貨後倉庫總有:73
說明:這個用不著分析了,過程和結果很明顯,思路還處於初級階段,以後會慢慢改進優化。如果您有好的建議,歡迎指正,交流促進進步!
多線程學習-基礎(十二)生產者消費者模型:wait(),sleep(),notify()實現