多线程系列之九:Worker Thread模式
一,Worker Thread模式
也叫ThreadPool(线程池模式)
二,示例程序
情景:
一个工作车间有多个工人处理请求,客户可以向车间添加请求。
请求类:Request
定义了请求的信息和处理该请求的方法
车间类:Channel
定义了车间里的工人,存放请求的容器。接收请求的方法,处理完请求后取出请求的方法
客户类:ClientThread
创建请求,并把请求交给车间
工人类:WorkerThread
处理请求
public class Request {
private final String name;
private final int number;
private static final Random random = new Random();
public Request(String name,int number){
this.name = name;
this.number = number;
}
/**
* 处理该请求的方法
*/
public void execute(){
System.out.println(Thread.currentThread().getName()+" executes "+this);
try {
Thread.sleep(random.nextInt(1000));
}catch (InterruptedException e){
}
}
@Override
public String toString() {
return " [ Request from "+ name + " NO." +number+" ] ";
}
}
public class Channel {
private static final int MAX_REQUEST = 100 ;
private final Request[] requestQueue;
private int tail;
private int head;
private int count;
private final WorkerThread[] threadPool;
public Channel(int threads){
this.requestQueue = new Request[MAX_REQUEST];
this.head = 0;
this.tail = 0;
this.count = 0;
threadPool = new WorkerThread[threads];
for (int i = 0; i < threadPool.length; i++) {
threadPool[i] = new WorkerThread("Worker-"+i,this);
}
}
/**
* 启动线程
*/
public void startWorkers(){
for (int i = 0; i < threadPool.length; i++) {
threadPool[i].start();
}
}
/**
* 接受请求
* @param request
*/
public synchronized void putRequest(Request request){
while (count >= requestQueue.length){
try{
wait();
}catch (InterruptedException e){
}
}
requestQueue[tail] = request;
tail = (tail + 1)%requestQueue.length;
count++;
notifyAll();
}
public synchronized Request takeRequest(){
while (count <= 0){
try {
wait();
}catch (InterruptedException e){
}
}
Request request = requestQueue[head];
head = (head + 1)%requestQueue.length;
count--;
notifyAll();
return request;
}
}
public class ClientThread extends Thread {
private final Channel channel;
private static final Random random = new Random();
public ClientThread(String name,Channel channel){
super(name);
this.channel = channel;
}
@Override
public void run() {
try {
for (int i = 0; true ; i++) {
Request request = new Request(getName(),i);
channel.putRequest(request);
Thread.sleep(random.nextInt(1000));
}
}catch (InterruptedException e){
}
}
}
public class WorkerThread extends Thread{
private final Channel channel;
public WorkerThread(String name,Channel channel){
super(name);
this.channel = channel;
}
@Override
public void run() {
while (true){
Request request = channel.takeRequest();
request.execute();
}
}
}
public class Test {
public static void main(String[] args) {
Channel channel = new Channel(5);
channel.startWorkers();
new ClientThread("aaa",channel).start();
new ClientThread("bbb",channel).start();
new ClientThread("ccc",channel).start();
}
}
三,使用场景
1,提高吞吐量
由于启动新线程需要花费时间,所以这个模式可以通过轮流反复的使用线程来提高吞吐量
2,容量控制
可以控制工人的数量(控制同时处理请求的线程的数量)
3,调用和执行的分离 (类似消息中间件)
Client角色负责发送工作请求,Worker角色负责处理请求。将方法的调用和执行分离开来
这样可以提高响应速度,调用方执行完后不必等待执行方,调用完成后可以做别的事情
四,通过java.util.concurrent包创建线程池
public class Request17 implements Runnable {
private final String name;
private final int number;
private static final Random random = new Random();
public Request17(String name,int number){
this.name = name;
this.number = number;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" executes "+this);
try {
Thread.sleep(random.nextInt(1000));
}catch (InterruptedException e){
}
}
@Override
public String toString() {
return " [ Request from "+ name + " NO." +number+" ] ";
}
}
public class ClientThread17 extends Thread {
private final ExecutorService executorService;
private static final Random random = new Random();
public ClientThread17(String name,ExecutorService executorService){
super(name);
this.executorService = executorService;
}
@Override
public void run() {
try {
for (int i = 0; true ; i++) {
Request17 request17 = new Request17(getName(),i);
executorService.execute(request17);
Thread.sleep(1000);
}
}catch (InterruptedException e){
}catch (RejectedExecutionException e){
System.out.println(getName()+ " : "+ e);
}
}
}
public class Test17 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
try {
new ClientThread17("aaa",executorService).start();
new ClientThread17("bbb",executorService).start();
new ClientThread17("ccc",executorService).start();
Thread.sleep(5000);
}catch (InterruptedException e){
}finally {
//主线程执行大约5秒后,关闭线程池。关闭线程池后,execute方法会被拒绝执行,并抛出异常 RejectedExecutionException异常啊
executorService.shutdown();
}
}
}
多线程系列之九:Worker Thread模式的更多相关文章
- Java Thread系列(九)Master-Worker模式
Java Thread系列(九)Master-Worker模式 Master-Worker模式是常用的并行设计模式. 一.Master-Worker 模式核心思想 Master-Worker 系统由两 ...
- 多线程 Worker Thread 模式
Worker是“工人”的意思,worker thread pattern中,工人线程(worker thread)会一次抓一件工作来处理,当没有工作可做时,工人线程会停下来等待心得工作过来. Work ...
- Java 设计模式系列(九)组合模式
Java 设计模式系列(九)组合模式 将对象组合成树形结构以表示"部分-整体"的层次结构.组合模式使得用户对单个对象的使用具有一致性. 一.组合模式结构 Component: 抽象 ...
- Worker Thread模式
工人线程Worker thread会逐个取回工作并进行处理,当所有工作全部完成后,工人线程会等待新的工作到来 5个工人线程从传送带取数据,3个传送工人线程将数据放入传送带 public class C ...
- java多线程系列15 设计模式 生产者 - 消费者模式
生产者-消费者 生产者消费者模式是一个非常经典的多线程模式,比如我们用到的Mq就是其中一种具体实现 在该模式中 通常会有2类线程,消费者线程和生产者线程 生产者提交用户请求 消费者负责处理生产者提交的 ...
- 多线程系列之十:Future模式
一,Future模式 假设有一个方法需要花费很长的时间才能获取运行结果.那么,与其一直等待结果,不如先拿一张 提货单.获取提货单并不耗费时间.这里提货单就称为Future角色获取Future角色的线程 ...
- 多线程系列之七:Read-Write Lock模式
一,Read-Write Lock模式 在Read-Write Lock模式中,读取操作和写入操作是分开考虑的.在执行读取操作之前,线程必须获取用于读取的锁.在执行写入操作之前,线程必须获取用于写入的 ...
- 多线程系列之四:Guarded Suspension 模式
一,什么是Guarded Suspension模式如果执行现在的处理会造成问题,就让执行处理的线程等待.这种模式通过让线程等待来保证实例的安全性 二,实现一个简单的线程间通信的例子 一个线程(Clie ...
- java多线程系列 目录
Java多线程系列1 线程创建以及状态切换 Java多线程系列2 线程常见方法介绍 Java多线程系列3 synchronized 关键词 Java多线程系列4 线程交互(wait和 ...
随机推荐
- Python 提案
学习Java 不可不知JSR,学习Python自然也得知道 PEP了 1- PEP简介 PEP是Python增强提案(Python Enhancement Proposal)的缩写.https://w ...
- 15个实用的PHP正则表达式
对于开发人员来说,正则表达式是一个非常有用的功能,它提供了 查找,匹配,替换 句子,单词,或者其他格式的字符串.这篇文章主要介绍了15个超实用的php正则表达式,需要的朋友可以参考下.在这篇文章里,我 ...
- 解决git push时发现有超过100M的文件时,删除文件后,发现还是提交不上去的问题
我这里故意放了一个超过100M的文件 后续,git add ,git commit 然后,git push 此时会发现出现了错误.如果,我们再这里直接在文件系统中删除这个大的文件,然后再次提交,会发现 ...
- C++中的字符串输入输出函数详解
常见的输入问题: 1.直接用cin输入(当然可以使用cout直接输出): 1)string s; cin >> s; //只接收回车键和空格前面所输入的字符!!!!! 一旦输入空格,cin ...
- DB2常见错误信息
000 00000 SQL语句成功完成01xxx SQL语句成功完成,但是有警告+012 01545 未限定的列名被解释为一个有相互联系的引用+098 01568 动态SQL语句用分号结束+100 0 ...
- 12.scrapy框架之递归解析和post请求
今日概要 递归爬取解析多页页面数据 scrapy核心组件工作流程 scrapy的post请求发送 今日详情 1.递归爬取解析多页页面数据 - 需求:将糗事百科所有页码的作者和段子内容数据进行爬取切持久 ...
- 用js显示系统当前日期
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- 阿里云windows server 2012 TIME_WAIT CLOSE_WAIT
新申请的阿里云windows server 2012 R2上部署安装了socket服务器,但客户端连接后老是断开(心跳包没有),服务假死(服务不断也走),客户端申请连接会也会死在cmd下输入指令 ne ...
- hash_hmac 签名
<?php /** * =========================================================== * Model_Base * Descriptio ...
- 【js】event(事件对象)详解
1.事件对象 Event 对象代表事件的状态,比如事件在其中发生的元素.键盘按键的状态.鼠标的位置.鼠标按钮的状态. 什么时候会产生Event 对象呢? 例如: 当用户单击某个元素的时候,我们给这个元 ...