多线程程序设计学习(6)Producer-Consumer模式
Producer-Consumer【生产消费者模式】
一:Producer-Consumer pattern的参与者
--->产品(蛋糕)
--->通道(传递蛋糕的桌子)
--->生产者线程(制造蛋糕的线程)
--->消费者线程(吃掉蛋糕的线程)
二:Producer-Consumer pattern模式什么时候使用
--->大量生产+大量消费的模式
三:Producer-Consumer pattern思考
--->【生产消费者模式】,肩负保护数据安全性使命的是通道参与者。通道参与者参与进行线程间的共享互斥,让生产着能正确将数据传递到消费者手中。
--->通道(桌子)的put和take方法都使用了【独木桥模式】,而生产者和消费者都不想依赖table类的详细实现,也就说,生产者不必理会其他线程,只管生产并put,同样消费者也不必理会其他线程,只管take就好。而线程的共享互斥,synchronized,wati,notifyAll这些考虑的多线程操作的代码,全都隐藏在通道table类里。提高了table的复用性。
--->生产者消费者模式,存在两方处理速率不同的话,必然造成一方等待,或占用通道大量内存的问题。
--->多线程合作的口决
线程的合作要想:放在中间的东西
线程的互斥要想:应该保护的东西
--->多生产者对单一消费者,如果情况合理,一方可以不用考虑互斥,就不用加锁,提升性能。
四进阶说明
--->习惯编写java多线程。当所调用的方法抛出,或内部抓住异常:InterruptedException.
==>通常传递给我们两个信息。(1)这是‘需要花点时间’的方法(2)这是‘可以取消’的方法
==>告诉我们方法内部有这三个选手:java.lang.Object类里的wait方法
java.lang.Thread类里的sleep方法
java.lang.Thread类里的join方法
--->需要花点时间的方法
wait==>执行wait方法的线程,进入wait set里休眠,等待notify,notifyAll唤醒。在休眠期间不会活动,因此需要花费时间。
sleep==>执行sleep,会暂停执行参数内所设置的时间,这也是需要花费时间
join==>会等待制定的线程结束为止。才执行本线程。也就是花费直到制定线程结束之前的这段时间
--->可以取消的方法。
因为需要花费时间,会降低程序的响应性,所以我们会希望像下面这样可以在中途放弃(取消)执行这个方法
1取消wait方法等待notify,notifyAll唤醒的操作
2取消sleep方法等待设置长度时间的操作
3取消join方法等待其他线程结束的操作
--->取消线程等待的详细解说
(1) A线程的实例为athread,线程体内部执行Thread.sleep(1000)时,想取消其睡眠状态。则需要B线程中取消。
--->在B线程中用athread.interrupt().
--->则A线程终止睡眠,并抛出或被抓住InterruptedException
--->这个时候A线程的catch块的代码,至关重要。
(2) A线程的实例为athread,线程体内部执行wait()时,想取消等待notify,notifyAll唤醒的操作。则需要B线程中取消。
--->在B线程体中用athread.interrupt().
--->则A线程终止等待状态,并尝试重新获取锁定。
--->获取锁定后,抛出或被抓住InterruptedException
--->这个时候A线程的catch块的代码,至关重要。
(3)A线程的实例为athread,线程体内部执行join(),想等待其他线程执行结束。则需要B线程中取消。
--->在B线程中用athread.interrupt().
--->则A线程终止睡眠,并抛出或被抓住InterruptedException
--->这个时候A线程的catch块的代码,至关重要。
--->线程对象.interrupt(),Thead.interrupted,线程对象.isinterrupted()区别
==>interrupt()让等待或休眠的线程变成中断状态,抛出异常
==>interrupted()检查线程的中断状态
是中断状态,返回true,并将中断状态修改成非中断状态
不是中断状态,返回false,不做任何操作
==>isinterrupted简单的检查线程是否为中断状态,是返回true,不是返回false,不做任何操作
Producer-Consumer案例
三个生产蛋糕的线程,三个消费蛋糕的线程,一个传递蛋糕的桌子。
传递蛋糕的桌子
package com.yeepay.sxf.thread5;
/**
* 在消费线程和生产线程中间起传递作用的桌子
* @author sxf
*
*/ public class Table {
//存放蛋糕的数组
private String[] cakes;
//下一个放蛋糕的位置
private int nextPut;
//下一个取蛋糕的位置
private int nextGet;
//蛋糕数组中蛋糕的数量
private int count;
//构造器
public Table (int count){
this.cakes=new String[count];
this.nextGet=0;
this.nextPut=0;
}
//存放蛋糕
public synchronized void putCakes(String cake) throws InterruptedException{
System.out.println("["+Thread.currentThread().getName()+"]put"+cake);
//警戒条件 如果桌子上蛋糕,慢了,就阻塞生产线程。
while (count>=cakes.length) {
wait();
}
//将蛋糕放入模拟队列
cakes[nextPut]=cake;
//算出下一个放蛋糕的位置
nextPut=(nextPut+1)%cakes.length;
//蛋糕数据量加1
count++;
//唤醒别的线程
notifyAll();
} //取蛋糕
public synchronized String takeCake() throws InterruptedException{
//判断桌子上是否有蛋糕,如果没有,阻塞线程
while (count<=0) {
wait();
}
//取出蛋糕
String cake=cakes[nextGet];
//计算出下一个取蛋糕的位置
nextGet=(nextGet+1)%cakes.length;
//蛋糕数量减一
count--;
//唤醒其他线程
notifyAll();
System.out.println("【"+Thread.currentThread().getName()+"】get"+cake);
return cake;
}
}
生产蛋糕的线程
package com.yeepay.sxf.thread5;
/**
* 制造蛋糕线程
* @author sxf
*
*/
public class MakeCakeThread implements Runnable{
//存放蛋糕的桌子
private Table table; //构造器
public MakeCakeThread(Table table) {
this.table=table;
} @Override
public void run() {
while (true) {
for (int i = 0; i <100; i++) { try {
//生产蛋糕,并放入
table.putCakes(Thread.currentThread().getName()+"的蛋糕"+i);
//当前线程休息1秒钟 Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} } } }
吃掉蛋糕的线程
package com.yeepay.sxf.thread5;
/**
* 吃蛋糕的线程
* @author sxf
*
*/
public class EatCakeThread implements Runnable {
//桌子
private Table table;
//构造器
public EatCakeThread(Table table){
this.table=table;
}
/**
* 线程体
*/
@Override
public void run() {
while(true){
try {
String cake=table.takeCake();
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} } }
测试类
package com.yeepay.sxf.thread5;
/**
* 测试类
* @author sxf
*
*/
public class Test { public static void main(String[] args) {
//声明一张桌子
Table table=new Table(4);
//声明生产蛋糕的线程
Thread makeThread1=new Thread(new MakeCakeThread(table));
makeThread1.setName("尚晓飞师傅");
Thread makeThread2=new Thread(new MakeCakeThread(table));
makeThread2.setName("范林军师傅");
Thread makeThread3=new Thread(new MakeCakeThread(table));
makeThread3.setName("黄栓林师傅"); //声明吃蛋糕的线程
Thread eatThread1=new Thread(new EatCakeThread(table));
eatThread1.setName("顾客1");
Thread eatThread2=new Thread(new EatCakeThread(table));
eatThread2.setName("顾客2");
Thread eatThread3=new Thread(new EatCakeThread(table));
eatThread3.setName("顾客3"); //启动线程
makeThread1.start();
makeThread2.start();
makeThread3.start();
eatThread1.start();
eatThread2.start();
eatThread3.start(); }
}
测试结果:
[尚晓飞师傅]put尚晓飞师傅的蛋糕0
[范林军师傅]put范林军师傅的蛋糕0
【顾客1】get尚晓飞师傅的蛋糕0
【顾客2】get范林军师傅的蛋糕0
[黄栓林师傅]put黄栓林师傅的蛋糕0
【顾客3】get黄栓林师傅的蛋糕0
[尚晓飞师傅]put尚晓飞师傅的蛋糕1
【顾客3】get尚晓飞师傅的蛋糕1
[范林军师傅]put范林军师傅的蛋糕1
【顾客1】get范林军师傅的蛋糕1
[黄栓林师傅]put黄栓林师傅的蛋糕1
【顾客2】get黄栓林师傅的蛋糕1
[尚晓飞师傅]put尚晓飞师傅的蛋糕2
多线程程序设计学习(6)Producer-Consumer模式的更多相关文章
- 多线程程序设计学习(2)之single threaded execution pattern
Single Threaded Execution Pattern[独木桥模式] 一:single threaded execution pattern的参与者--->SharedResourc ...
- 多线程程序设计学习(3)immutable pattern模式
Immutable pattern[坚不可摧模式] 一:immutable pattern的参与者--->immutable(不变的)参与者 1.1:immutable参与者是一个 ...
- 多线程程序设计学习(5)balking模式和timed模式
Balking[返回模式]timed[超时模式]一:balking pattern的参与者--->GuardedObject(被警戒的对象) --->该模式的角色:模拟修改警戒对象的线程, ...
- 多线程程序设计学习(4)guarded suspension模式
Guarded Suspension[生产消费者模式] 一:guarded suspension的参与者--->guardedObject(被防卫)参与者 1.1该 ...
- 多线程程序设计学习(9)worker pattern模式
Worker pattern[工作模式]一:Worker pattern的参与者--->Client(委托人线程)--->Channel(通道,里边有,存放请求的队列)--->Req ...
- 多线程程序设计学习(13)Active Object pattern
Active Object[接收异步消息的对象] 一:Active Object的参与者--->客户端线程(发起某种操作请求处理)--->代理角色(工头)--->实际执行者(工人)- ...
- 多线程程序设计学习(12)Thread-soecific storage pattern
Thread-Specific-Storage[线程保管箱] 一:Thread-Specific Storage的参与者--->记录日志的线程(ClientThread)--->负责获取不 ...
- 多线程程序设计学习(11)Two-phapse-Termination pattern
Two-phapse-Termination[A终止B线程] 一:Two-phapse-Termination的参与者--->A线程--->B线程 二:Two-phapse-Termina ...
- 多线程程序设计学习(10)Future pattern
Future pattern[订单取货模式] 一:Future pattern的参与者--->Client(客户需求)--->Host(蛋糕门店)--->Data(票据和蛋糕的接口) ...
随机推荐
- Hello Stacked Column Chart
<navigation:Page xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/to ...
- MQ 2035(MQRC_NOT_AUTHORIZED)
当使用MQ7.1或7.5时,如果使用MQ管理员账号去连接MQ服务器,可能会报以下的错误,提示你权限不足. 2035 MQRC_NOT_AUTHORIZED 在之前的版本中是没有这个问题的. 原因是在7 ...
- EXTJS4.2 控件之Grid getRowClass 添加行背景色
css 样式: /*交流管理系统 开始*/ tr.x-grid-record-blue .x-grid-td { background: #87CEFF; }/*grid 行颜色*/ tr.x-gri ...
- Java调用SQLCMD遇到的问题
今天用Java调用SQLCMD命令时,一直提示找不到SQLCMD命令,但是通过CMD命令确可以使用,因为我的sqlcmd是新安装的,所以重新配置了新的path路径,而cmd可以调用是因为重新开一个cm ...
- js检测对象的类型
在JavaScript中,想要判断某个对象值属于哪种内置类型,最靠谱的做法就是通过Object.prototype.toString方法. 示例: var array=[1,2,3]; Object. ...
- CQRS学习——Dpfb以及其他[引]
[Dpfb的起名源自:Ddd Project For Beginer,这个Beginer自然就是博主我自己了.请大家在知晓这是一个入门项目的事实上,怀着对入门者表示理解的心情阅读本系列.不胜感激.] ...
- SQL的表连接
每天给自己扫盲,让自己变得越博学. 继续学习<程序员的SQL金典>,这回我们来看看表连接相关的内容.表连接的相关知识在实际的项目开发当中,使用非常广. 所谓表连接,就是通过关联多张表,从而 ...
- 关于ax+by=c的解x,y的min(|x|+|y|)值问题
首先我们移动一下项,并强行让a>b. 然后我们可以画出这样一个图像 我们发现,在线段l与x轴交点处的下方,x,y的绝度值是递增的,所以我们不考虑那个最小点在下端. 之后我们发现在点的上端,因为斜 ...
- 团体程序设计天梯赛-练习集L1-017. 到底有多二
L1-017. 到底有多二 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 一个整数“犯二的程度”定义为该数字中包含2的个数与其 ...
- jsp 获取表单值, 提交类型为multipart/form-data处理
//tt.jsp<script type="text/javascript"> function doSubmit(){ alert("aaaaaa" ...