一,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. python3编写网络爬虫23-分布式爬虫

    一.分布式爬虫 前面我们了解Scrapy爬虫框架的基本用法 这些框架都是在同一台主机运行的 爬取效率有限 如果多台主机协同爬取 爬取效率必然成倍增长这就是分布式爬虫的优势 1. 分布式爬虫基本原理 1 ...

  2. 汲取营养的blog专栏

    网路上博客专栏是学习提升.思考深化的好途径,目前发现的博客价值高的平台: (1)EETOP www.eetop.cn (2)CSND www.csdn.net (3)cnblog www.cnblog ...

  3. node.js—File System(文件系统模块)

    文件系统模块概述 该模块是核心模块,提供了操作文件的一些API,需要使用require导入后使用,通过 require('fs') 使用该模块 文件 I/O 是由简单封装的标准 POSIX 函数提供的 ...

  4. Doc2vec实现原理

    论文来源:https://www.eecs.yorku.ca/course_archive/2016-17/W/6412/reading/DistributedRepresentationsofSen ...

  5. 转://Linux下误删除/home目录的恢复方法

    一般情况下,我们在安装Oracle数据库的时候,都会创建一个Oracle用户,用该用户来安装和管理Oracle.Oracle用户的根目录就是/home/oracle. 通常安装Oracle数据库是按照 ...

  6. 转://因触发器限制导致oracle用户登录失败

    使用PL/SQL DEV登录数据库时,出现如下错误 手工创建了test用户,通过dev工具登录没问题.怀疑数据库中有些用户限制了登录的.再看错误编号:ORA-20001,oracle保留的异常错误号范 ...

  7. PHP创建socket服务

    PHP可以创建socket服务. 先熟悉几个php网络方面的函数,操作手册地址  http://php.net/manual/zh/ref.sockets.php 简单介绍下socket,它表示套接字 ...

  8. Java虚拟机性能监测工具Visual VM与OQL对象查询语言

    1.Visual VM多合一工具 Visual VM是一个功能强大的多合一故障诊断和性能监控的可视化工具,它集成了多种性能统计工具的功能,使用 Visual VM 可以代替jstat.jmap.jha ...

  9. Python 学习 第十四篇:命名元组

    Python的元组不能为元组内部的数据进行命名,而 collections.namedtuple 可以来构造一个含有字段名称的元组类,命名元组可以通过逗号+字段名来获取元素值: collections ...

  10. .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中

    不知你是否见过 try { } finally { } 代码中,try 块留空,而只往 finally 中写代码的情况呢?这种写法有其特殊的目的. 本文就来说说这种不一样的写法. 你可以点开这个链接查 ...