多线程学习-基础(十二)生产者消费者模型: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
package com.jason.proCusModels;
/**
* 产品类
* @function
* @author 小风微凉
* @time 2018-4-26 下午8:00:40
*/
public class Product {
//产品名称
private String pName;
//产品编号
private String proNo;
public Product(String pName,String proNo){
this.pName=pName;
this.proNo=proNo;
}
//设置getter方法
public String getpName() {
return pName;
}
public String getProNo() {
return proNo;
}
//重写toString方法
@Override
public String toString() {
return "产品名称:"+this.pName+",产品编号:"+this.proNo;
}
}
仓库类Warehouse
package com.jason.proCusModels;
import java.util.ArrayList;
import java.util.List;
/**
* 仓库类
* @function
* @author 小风微凉
* @time 2018-4-26 下午7:59:34
*/
public class Warehouse {
//仓库名称
private String name;
//仓库最大容量上限
private int MAX_COUNT=100;
//设置仓库货物预警下限:此处可以加设进货策略,不同的缺货程度,设置不同的进货速度(以后再补充)
private int MIN_COUNT=20;
//仓库存放商品的容器
public static List<Product> proList;
//静态块
static{
proList=new ArrayList<Product>();
}
//构造器
public Warehouse(String name){
this.name=name;
}
/**
* 仓库进货
* @param count 进货数量
*/
public synchronized void Purchase(int count){
//判断当前货物+count是否超过上限 如果超过,则停止进货 只允许出货
int currCount=proList.size();
if(currCount+count>MAX_COUNT){
this.notify();//唤醒其他线程
try {
System.out.println(Thread.currentThread().getName()+"准备进货:"+count+"个产品,当前仓库货物有:"+currCount+"个,【货物超过仓库存放上限:"+MAX_COUNT+"】,已经停止进货");
this.wait();//停止进货
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();//中断线程
}
}else{//判断:当前货物+count没有超过上限 则可以继续进货
if(currCount<=MIN_COUNT){
System.out.println("当前仓库剩余货物数量,在最低警戒线一下,请抓紧时间补货!!!!!!!");
}
//开始进货
for(int i=0;i<count;i++){
//拿到产品
Product prod=new Product("IphoneX", "*");//编号随意,暂时不会用到
//入库
proList.add(prod);
}
System.out.println(Thread.currentThread().getName()+"准备进货:"+count+"个产品,当前仓库货物有:"+currCount+"个,进货后仓库总有:"+proList.size());
}
try {
Thread.sleep(1000);//放置一个线程占用cpu过久
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 仓库出货
* @param count·出货数量
*/
public synchronized void Shipments(int count){
//如果当前仓库货物余货为0 或者出货数量<count 则停止出货 开始进货
int currCount=proList.size();
if(currCount==0 || currCount<count){
this.notify();//唤醒其他线程
try {
System.out.println(Thread.currentThread().getName()+"准备出货:"+count+"个产品,当前仓库货物有:"+currCount+"个,【货物短缺,请尽快进货】,已经停止出货");
this.wait();//停止出货
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();//中断线程
}
}else{//仓库货物充足,可继续出货
//出货
proList=proList.subList(count, proList.size());
System.out.println(Thread.currentThread().getName()+"准备出货:"+count+"个产品,当前仓库货物有:"+currCount+"个,出货后仓库总有:"+proList.size());
}
try {
Thread.sleep(1000);//放置一个线程占用cpu过久
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 拿到仓库容器
* @return
*/
public static List<Product> getProList() {
return proList;
}
}
生产者线程(实现Runnable)Producer
package com.jason.proCusModels;
/**
* 生产者类(线程)
* @function
* @author 小风微凉
* @time 2018-4-26 下午7:57:47
*/
public class Producer implements Runnable{
//生产者名称
private String name;
//仓库对象
private Warehouse whose;//这样写只是为了让关系更加清晰 实际仓库容器:Warehouse.proList
//消费产品数量
private int threadCount;
//构造器
public Producer(String name,int threadCount,Warehouse whose){
this.name=name;
this.whose=whose;
this.threadCount=threadCount;
}
public void run() {
Thread.currentThread().setName(this.name);
//开始进货
while(true){
whose.Purchase(threadCount);
}
}
}
消费者线程(实现Runnable)Consumer
package com.jason.proCusModels;
/**
* 消费者类(线程)
* @function
* @author 小风微凉
* @time 2018-4-26 下午7:58:59
*/
public class Consumer implements Runnable{
//消费者名称
private String name;
//仓库对象
private Warehouse whose;//这样写只是为了让关系更加清晰 实际仓库容器:Warehouse.proList
//消费产品数量
private int threadCount;
//构造器
public Consumer(String name,int threadCount,Warehouse whose){
this.name=name;
this.whose=whose;
this.threadCount=threadCount;
}
public void run() {
Thread.currentThread().setName(this.name);
//开始出货
while(true){
whose.Shipments(threadCount);
}
}
}
一个启动类ThreadStart
package com.jason.proCusModels;
/**
* 多线程学习
* @function 生产者消费者模型启动类
* @author 小风微凉
* @time 2018-4-26 下午8:51:56
*/
public class ThreadStart {
/**
* 启动项
* @param args
*/
public static void main(String[] args) {
//创建一个仓库
Warehouse whose=new Warehouse("1号仓库");
//创建10个生产者线程
for(int i=1;i<=10;i++){
new Thread(new Producer(i+"号生产者",(int)(Math.random()*10+1),whose)).start();
}
//创建15个消费者线程
for(int i=1;i<=15;i++){
new Thread(new Consumer(i+"号消费者",(int)(Math.random()*10+1),whose)).start();
}
}
}
运行结果:(仅截取部分结果)
当前仓库剩余货物数量,在最低警戒线一下,请抓紧时间补货!!!!!!!
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()实现的更多相关文章
- python_way ,day11 线程,怎么写一个多线程?,队列,生产者消费者模型,线程锁,缓存(memcache,redis)
python11 1.多线程原理 2.怎么写一个多线程? 3.队列 4.生产者消费者模型 5.线程锁 6.缓存 memcache redis 多线程原理 def f1(arg) print(arg) ...
- java多线程:线程间通信——生产者消费者模型
一.背景 && 定义 多线程环境下,只要有并发问题,就要保证数据的安全性,一般指的是通过 synchronized 来进行同步. 另一个问题是,多个线程之间如何协作呢? 我们看一个仓库 ...
- Java多线程(九):生产者消费者模型
生产者消费者模型 生产者:生产任务的个体: 消费者:消费任务的个体: 缓冲区:是生产者和消费者之间的媒介,对生产者和消费者解耦. 当 缓冲区元素为满,生产者无法生产,消费者继续消费: 缓冲区元素为空, ...
- Python多线程的简单实现(生产者消费者模型)
__author__ = "JentZhang" import time, threading, queue q = queue.Queue(maxsize=) # 声明队列 de ...
- 学习了解 Exchanger - 实现生产者消费者模型
例子很简单 Exchanger可以理解为消息队列或者说是一个通信管道,从一边拿到消息,另外一边进行消费. 不过这个是同步实现的,消费者在exchange之前,生产者一直处于等待状态,而不是一直生产. ...
- C++学习基础十二——纯虚函数与抽象类
一.C++中纯虚函数与抽象类: 1.含有一个或多个纯虚函数的类成为抽象类,注意此处是纯虚函数,而不是虚函数. 2.如果一个子类继承抽象类,则必须实现父类中的纯虚函数,否则该类也为抽象类. 3.如果一个 ...
- Python3学习之路~9.4 队列、生产者消费者模型
一 队列queue 当必须在多个线程之间安全地交换信息时,队列在线程编程中特别有用. 队列的作用:1.解耦,使程序直接实现松耦合 2.提高处理效率 列表与队列都是有顺序的,但是他们之间有一个很大的区别 ...
- Python多线程-生产者消费者模型
用多线程和队列来实现生产者消费者模型 # -*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" import threading imp ...
- Day034--Python--锁, 信号量, 事件, 队列, 生产者消费者模型, joinableQueue
进程同步: 1. 锁 (重点) 锁通常被用来实现对共享资源的同步访问.为每一个共享资源创建一个Lock对象,当你需要访问该资源时,调用acquire方法来获取锁对象(如果其它线程已经获得了该锁, ...
- python 并发编程 多进程 生产者消费者模型介绍
一 生产者消费者模型介绍 为什么要使用生产者消费者模型 生产者指的是生产数据的任务,消费者指的是处理数据的任务, 生产数据目的,是为了给消费者处理. 在并发编程中,如果生产者处理速度很快,而消费者处理 ...
随机推荐
- [SPOJ10707]Count on a tree II
luogu 题意 给定一个n个节点的树,每个节点表示一个整数,问u到v的路径上有多少个不同的整数. sol 也就是路径数颜色.树上莫队板子题. 我这种分块的姿势貌似是假的. 所以跑的是最慢的QAQ. ...
- 门禁 IC卡 ID 卡 RFID 手环 NFC 银行卡 手机模拟门禁
门禁 IC卡 ID 卡 RFID 手环 NFC 银行卡 手机模拟门禁 原因 最近给公司换了一个门禁. 旧的门禁按键面板已经破了. 不支持我的手环. 按了密码后竟然要按 #. 相关信息 查了资料记录一下 ...
- git之cherry-pick
当想把当前分支提交的代码,也在其他分支提交,那可以用cherry-pick命令. 1 假设在master分支commit的id为:abc12345; 2 切换到其他分支,如develop分支; 3 在 ...
- SpringCloud组件的简单介绍
springcloud官网springcloud中文网站 最近开始接触springcloud,所以先了解了一下最最基本概念. Spring Cloud ConfigSpring配置管理工具包,让你可以 ...
- (转)Dynamic Web project转成Maven项目
本文转载自:http://my.oschina.net/twosnail/blog/369125 1.新建Dynamic Web Project 1.File -> New -> Othe ...
- delphi 10.2.2.2004 Tokyo 安装步骤
delphi 各版本的安装,其XX工具都附有详细说明.遵守其安装步骤,很容易成功. 本教就以 delphi 10.2.2.2004 为例,演示一下整个安装过程.其它各版本就自行尝试. 附: delph ...
- leetcode424
public class Solution { public int CharacterReplacement(string s, int k) { int len = s.Length; ]; , ...
- docker 笔记 (5)常用命令
images 显示镜像列表 history 显示镜像构建历史 commit 从容器创建新镜像 build 从 Dockerfile 构建镜像 tag 给镜像打 ta ...
- URL与HTTP介绍
一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) 通过1个URL,能找到互联网上唯一的1个资源 URL就是资源的地址.位置,互联网上的每个资源 ...
- 杀死tomcat进程
由于tomcat运行时eclipse非法关闭,导致tomcat进程没有关闭,再次启动eclipse,启动tomcat会报tomcat不能启动,且指出端口被占用.笔者解决方案如下: 方案一:重启电脑,简 ...