多线程学习之三生产者消费者模式Guarded Suspension
Guarded Suspension【生产消费者模式】
一:guarded suspension的参与者
--->guardedObject(被防卫)参与者
1.1该参与者拥有一个被防卫的方法(getRequest),如果警戒条件达成,则执行。警戒条件不达成,则线程进入wait set
1.2该参与者还拥有一个改变参与者状态的方法(putRequest)。参与者的状态影响着警戒条件的是否达成。
--->该模式的角色:生产端线程,消费端线程,传递数据的摇篮(被防卫的参与者)
二:guarded suspension模式什么时候使用
--->适合交易系统使用。客户端下单,服务端处理订单。高并发,大量数据处理的模式,增强服务的吞吐量
三:guarded suspension思考
--->与该模式共通的三个特征
3.1:有循环存在
3.2:有条件测试
3.3:有因某种原因的等待
---> guarded wait 被阻断而等待
等待端范例:
while(条件){
wait();
}
唤醒端范例:
条件=true
notifyAll();
---> busy wait 忙碌地等待
yield,尽可能把优先级交给其他线程,那个线程调用此方法,那个线程暂时一次让出CPU调度权。至于能否暂停,实际看cpu是否去掉别的线程。我主动
放弃一次,至于cpu走不走,看cpu的。yield不会解除锁定,所以这段代码不可写在snychronized里。而ready字段必须声明成
volatile
等待端范例:
while(ready){
Thead.yield();
}
唤醒端范例:
ready=true
---> spin lock 旋转而锁定
旋转而锁定的意思,表现出条件成立前while循环不断"旋转"的样子,spin lock有时意思与guarded wait相同,有时则与busy
wait相同。另外,有时候则是指一开始使用busy wait ,之后再切换成guarded wait方式。另外有些硬件实现的同步机制
--->polling
" 进行舆论调查"的意思,反复检查某个事件是否发生,当发生时就进行对应的处理。
请求实体类
1 /** 2 * 3 */ 4 package com.benxq.thread4; 5 6 /** 7 * 模拟请求实体 8 * Created by qucf on 2015年10月22日. 9 */ 10 public class RequestEntity { 11 12 //请求人的名称 13 private String name; 14 15 //线程的名称 16 private String clientThreadName; 17 18 19 public RequestEntity() { 20 super(); 21 } 22 23 /** 24 * @param name 25 * @param clientThreadName 26 */ 27 public RequestEntity(String name, String clientThreadName) { 28 super(); 29 this.name = name; 30 this.clientThreadName = clientThreadName; 31 } 32 33 public String getName() { 34 return name; 35 } 36 37 public void setName(String name) { 38 this.name = name; 39 } 40 41 public String getClientThreadName() { 42 return clientThreadName; 43 } 44 45 public void setClientThreadName(String clientThreadName) { 46 this.clientThreadName = clientThreadName; 47 } 48 49 @Override 50 public String toString() { 51 return "生产者:"+clientThreadName+"生产者生产的产品"+name+"被消费"; 52 } 53 }
请求实体队列类
1 /** 2 * 3 */ 4 package com.benxq.thread4; 5 6 import java.util.LinkedList; 7 8 /** 9 * 模拟请求队列 10 * Created by qucf on 2015年10月22日. 11 */ 12 public class RequestQueue { 13 14 //模拟队列容器 15 private LinkedList<RequestEntity> list=new LinkedList<RequestEntity>(); 16 17 //从队列中取出数据 18 public synchronized RequestEntity getRequestEntity(){ 19 //当容器中的数据为0时进入等待状态 20 while(list.size()<=0){ 21 try { 22 wait(); 23 } catch (InterruptedException e) { 24 // TODO Auto-generated catch block 25 e.printStackTrace(); 26 } 27 } 28 //如果不为空,返回第一个请求,并从集合中删除该请求 29 return list.removeFirst(); 30 } 31 32 //往队列中加入数据 33 public synchronized void putRequestEntity(RequestEntity entity){ 34 //将加入的数据加入队列尾部 35 list.addLast(entity); 36 //唤醒所有的线程 37 notifyAll(); 38 } 39 40 }
生产线程
1 /** 2 * 3 */ 4 package com.benxq.thread4; 5 6 import java.util.Random; 7 8 /** 9 * 模拟请求线程 10 * Created by qucf on 2015年10月22日. 11 */ 12 public class ClientThread implements Runnable{ 13 14 //存放请求的队列 15 private RequestQueue queue; 16 17 //随机数 18 private Random random; 19 20 //线程名称 21 private String name; 22 23 24 25 /** 26 * @param queue 27 * @param random 28 * @param name 29 */ 30 public ClientThread(RequestQueue queue, Random random, String name) { 31 super(); 32 this.queue = queue; 33 this.random = random; 34 this.name = name; 35 } 36 37 38 39 @Override 40 public void run() { 41 42 for (int i = 0; i < 5; i++) { 43 //生成一个请求 44 RequestEntity entity=new RequestEntity("No"+i, name); 45 46 //将请求放入到队列中 47 queue.putRequestEntity(entity); 48 49 //让线程休息几秒 50 try { 51 Thread.sleep(1000); 52 } catch (InterruptedException e) { 53 // TODO Auto-generated catch block 54 e.printStackTrace(); 55 } 56 } 57 } 58 }
消费线程
1 /** 2 * 3 */ 4 package com.benxq.thread4; 5 6 import java.util.Random; 7 8 /** 9 * 消费线程 10 * Created by qucf on 2015年10月22日. 11 */ 12 public class ServiceThread implements Runnable{ 13 14 //持有线程的队列 15 private RequestQueue queue; 16 //随机数 17 private Random random; 18 //线程名 19 private String name; 20 21 @Override 22 public void run() { 23 while(true){ 24 RequestEntity entiry=queue.getRequestEntity(); 25 System.out.println("消费线程"+name+"----->"+entiry.toString()); 26 try { 27 Thread.sleep(random.nextInt(random.nextInt(1000))); 28 } catch (InterruptedException e) { 29 // TODO Auto-generated catch block 30 e.printStackTrace(); 31 } 32 } 33 } 34 35 /** 36 * @param queue 37 * @param random 38 * @param name 39 */ 40 public ServiceThread(RequestQueue queue, Random random, String name) { 41 super(); 42 this.queue = queue; 43 this.random = random; 44 this.name = name; 45 } 46 47 48 }
主线程
1 /** 2 * 3 */ 4 package com.benxq.thread4; 5 6 import java.util.Random; 7 8 /** 9 * 主线程 10 * Created by qucf on 2015年10月22日. 11 */ 12 public class Test { 13 14 15 public static void main(String[] args) { 16 //声明一个队列 17 RequestQueue queue=new RequestQueue(); 18 19 //生产者线程 20 Thread sc1=new Thread(new ClientThread(queue, new Random(), "QQ客户端")); 21 Thread sc2=new Thread(new ClientThread(queue, new Random(), "ALIBABA客户端")); 22 23 //消费者线程 24 Thread xf1=new Thread(new ServiceThread(queue, new Random(), "渠道1")); 25 Thread xf2=new Thread(new ServiceThread(queue, new Random(), "渠道2")); 26 Thread xf3=new Thread(new ServiceThread(queue, new Random(), "渠道3")); 27 28 //开启线程 29 sc1.start(); 30 sc2.start(); 31 32 xf1.start(); 33 xf2.start(); 34 xf3.start(); 35 } 36 }