一,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模式的更多相关文章

  1. Java Thread系列(九)Master-Worker模式

    Java Thread系列(九)Master-Worker模式 Master-Worker模式是常用的并行设计模式. 一.Master-Worker 模式核心思想 Master-Worker 系统由两 ...

  2. 多线程 Worker Thread 模式

    Worker是“工人”的意思,worker thread pattern中,工人线程(worker thread)会一次抓一件工作来处理,当没有工作可做时,工人线程会停下来等待心得工作过来. Work ...

  3. Java 设计模式系列(九)组合模式

    Java 设计模式系列(九)组合模式 将对象组合成树形结构以表示"部分-整体"的层次结构.组合模式使得用户对单个对象的使用具有一致性. 一.组合模式结构 Component: 抽象 ...

  4. Worker Thread模式

    工人线程Worker thread会逐个取回工作并进行处理,当所有工作全部完成后,工人线程会等待新的工作到来 5个工人线程从传送带取数据,3个传送工人线程将数据放入传送带 public class C ...

  5. java多线程系列15 设计模式 生产者 - 消费者模式

    生产者-消费者 生产者消费者模式是一个非常经典的多线程模式,比如我们用到的Mq就是其中一种具体实现 在该模式中 通常会有2类线程,消费者线程和生产者线程 生产者提交用户请求 消费者负责处理生产者提交的 ...

  6. 多线程系列之十:Future模式

    一,Future模式 假设有一个方法需要花费很长的时间才能获取运行结果.那么,与其一直等待结果,不如先拿一张 提货单.获取提货单并不耗费时间.这里提货单就称为Future角色获取Future角色的线程 ...

  7. 多线程系列之七:Read-Write Lock模式

    一,Read-Write Lock模式 在Read-Write Lock模式中,读取操作和写入操作是分开考虑的.在执行读取操作之前,线程必须获取用于读取的锁.在执行写入操作之前,线程必须获取用于写入的 ...

  8. 多线程系列之四:Guarded Suspension 模式

    一,什么是Guarded Suspension模式如果执行现在的处理会造成问题,就让执行处理的线程等待.这种模式通过让线程等待来保证实例的安全性 二,实现一个简单的线程间通信的例子 一个线程(Clie ...

  9. java多线程系列 目录

    Java多线程系列1 线程创建以及状态切换    Java多线程系列2 线程常见方法介绍    Java多线程系列3 synchronized 关键词    Java多线程系列4 线程交互(wait和 ...

随机推荐

  1. Hibernate 5 入门指南-基于映射文件

    由于Hibernate 4版本混乱,Hibernate 3有些过时,Hibernate 5的开发文档尚不完善,所以构建一份简单的Hibernate 5的入门指南 注:案例参考Hibernate 官方参 ...

  2. php函数long2ip与ip2long()

    long2ip - Converts an long integer address into a string in (IPv4) Internet standard dotted format s ...

  3. 【Linux基础】VI命令模式下大小写转换

    [开始位置] ---- 可以指定开始的位置,默认是光标的当前位置 gu ---- 把选择范围全部小写 gU ---- 把选择范围全部大写 [结束位置] ---- 可以跟着类似的w,6G,gg等定位到错 ...

  4. windows通过node环境搭建安装npm,cnpm,vue-cli

    1首先下载node,官网地址:https://nodejs.org/en/ 左边是稳定版,右边是最新版,安装过程一样,我选择的是稳定版. 按照步骤一步一步的安装就行,注意路径就可以了. 友情链接:ht ...

  5. centos7下安装docker(17docker监控---docker自带监控命令)

    Docker自带的监控子命令 1.docker ps:docker ps -a这是我们常用的查看容器状态的命令 docker  container ls和docker ps的功能一样 2.docker ...

  6. Tmux的快捷键

    Ctrl+b 激活控制台:此时以下按键生效 系统操作 ? 列出所有快捷键:按q返回 d 脱离当前会话:这样可以暂时返回Shell界面,输入tmux attach能够重新进入之前的会话 D 选择要脱离的 ...

  7. [转]Oracle 清除incident和trace -- ADRCI用法

    在oracle11g中,dump file的目录已经有所改变,bdump和udump整合到trace中,cdump独立出一个. E:\ora11g\app\Administrator\diag\rdb ...

  8. pycharm 安装及使用

    pycharm 的使用: IDE 集成开发环境(Integrated Development Environment) VIM 经典的Linux下的文本编辑器 EMACS: Linux文本编辑器,比v ...

  9. Raid卡介绍

    raid0条带卷 最少需要一块硬盘 可以把所有硬盘的容量都叠加在一起,可以拥有很高的读写速度,硬盘空间也能得到很好的利用 但是只要其中一块硬盘换了,数据就全丢失了 raid1镜像卷 最少需要两块硬盘, ...

  10. ORA-01034:ORACLE not available ORA-27101:shared memory realm does not exit

    ORA-01034:ORACLE not available ORA-27101:shared memory realm does not exit   ERROR: ORA-01034:ORACLE ...