多线程学习-基础生产者消费者模型: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() 的生产者/消费者模式

多线程(基础2)

多线程(基础2)

基于线程实现的生产者消费者模型(Object.wait(),Object.notify()方法)

多线程--生产者/消费者线程模型

多线程编程实践——实现生产者消费者模型