多线程学习-基础生产者消费者模型:wait(),sleep(),notify()实现
Posted 小风微灵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程学习-基础生产者消费者模型: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 package com.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; 15 this.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()实现的主要内容,如果未能解决你的问题,请参考以下文章
java多线程15 :wait()和notify() 的生产者/消费者模式