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

说明:这个用不着分析了,过程和结果很明显,思路还处于初级阶段,以后会慢慢改进优化。如果您有好的建议,欢迎指正,交流促进进步!

原文地址:https://www.cnblogs.com/newwind/p/8955201.html

时间: 2024-10-13 23:52:18

多线程学习-基础(十二)生产者消费者模型:wait(),sleep(),notify()实现的相关文章

JAVA学习笔记(四十二)-生产者消费者模型

wait().notify() /* * wait().notify() * * 1.两个方法都只能在synchronized代码块中执行,因为要对持有锁的线程操作,只有同步中才有锁 * 2.两个方法在操作同步中的线程时,必须要标识所操作线程持有的对象锁 * 3.等待和唤醒必须是同一个对象锁 */ public class Test05 { public static void main(String[] args) { MyThread3 mt=new MyThread3(); Thread

13.1 多线程操作共享内存、生产者消费者模型、多线程服务器框架

生产者消费者模型如下: 程序如下: 1 #include <unistd.h> 2 #include <sys/types.h> 3 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <errno.h> 7 #include <string.h> 8 9 #include <pthread.h> 10 11 int g_Count = 0; 12 13 int nN

学习了解 Exchanger - 实现生产者消费者模型

例子很简单 Exchanger可以理解为消息队列或者说是一个通信管道,从一边拿到消息,另外一边进行消费. 不过这个是同步实现的,消费者在exchange之前,生产者一直处于等待状态,而不是一直生产. 代码如下: package exchange; import java.util.concurrent.Exchanger; public class ExchangerDemo { final static Exchanger<String> exchanger = new Exchanger&

C++学习基础十二——纯虚函数与抽象类

一.C++中纯虚函数与抽象类: 1.含有一个或多个纯虚函数的类成为抽象类,注意此处是纯虚函数,而不是虚函数. 2.如果一个子类继承抽象类,则必须实现父类中的纯虚函数,否则该类也为抽象类. 3.如果一个类中含有虚函数,则必须将该类的析构函数声明为虚函数. 4.虚函数与纯虚函数的声明: virtual void draw();//虚函数 virtual void draw() = 0;//纯虚函数 5.C++中支持两种多态性: 编译时多态:通过重载函数实现. 运行时多态:通过虚函数实现. 二.Jav

多线程学习-基础(二)线程状态装换

一.线程状态转换 下面的这个图非常重要!你如果看懂了这个图,那么对于多线程的理解将会更加深刻 状态说明:(1)新建状态(New):新创建了一个线程对象.(2)就绪状态(Runnable):线程被创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行的线程池中,变得可运行,等待获取cpu的使用权限.(3)运行状态(Running):就绪状态的线程获取了cpu的使用权,执行程序代码.(4)阻塞状态(Blocked):阻塞状态是线程由于某种原因放弃了cpu的使用权,暂时停止运行,直到

生产者消费者模型实现多线程异步交互

[Python之旅]第六篇(五):生产者消费者模型实现多线程异步交互 消息队列 生产者消费者模型 多线程异步交互 摘要:  虽然标题是"生产者消费者模型实现多线程异步交互",但这里要说的应该还包括Python的消息队列,因为这里多线程异步交互是通过Python的消息队列来实现的,因此主要内容如下: 1 2 3 4 1.生产者消费者模型:厨师做包子与顾客吃包子 2.Python的消息队列 3.利用... 虽然标题是"生产者消费者模型实现多线程异步交互",但这里要说的应

1-7 生产者消费者模型

一 生产者消费者模型介绍 为什么要使用生产者消费者模型 生产者指的是生产数据的任务,消费者指的是处理数据的任务,在并发编程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据.同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者.为了解决这个问题于是引入了生产者和消费者模式. 什么是生产者和消费者模式 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生

Python生产者消费者模型

用多线程和队列来实现生产者消费者模型 # -*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" import threading import queue import time q = queue.Queue() def Producer(name): count = 1 while True: q.put("面包%s" %count) print("[%s]做了[%s]个面包" %(name,cou

Java多线程(十):BlockingQueue实现生产者消费者模型

BlockingQueue BlockingQueue.解决了多线程中,如何高效安全"传输"数据的问题.程序员无需关心什么时候阻塞线程,什么时候唤醒线程,该唤醒哪个线程. 方法介绍 BlockingQueue是Queue的子类 void put(E e) 插入指定元素,当BlockingQueue为满,则线程阻塞,进入Waiting状态,直到BlockingQueue有空闲空间再继续. 这里以ArrayBlockingQueue为例进行分析 void take() 队首出队,当Bloc