多线程 Worker Thread 模式
Worker是“工人”的意思,worker thread pattern中,工人线程(worker thread)会一次抓一件工作来处理,当没有工作可做时,工人线程会停下来等待心得工作过来。
Worker Thread也叫做background thread,另外,也有人把视点放在管理工人线程的地方,称之为Thread Pool。
最近闲时在看《Java多线程设计模式》,很不错,语言浅显易懂,而且编排也好,很有启发性,现在挑其中一章来写写心得
worker thread是我们平时用的很多的一种多线程模式,只不过我们常常不把它当模式罢了。基本内容是:有一个流水线(channel),流水线一端有客户线程client,另一端有工人线程worker,客户不断把新的任务(request)放入流水线,工人在另一头获得任务,并执行,客户和工人的数量可多可少,就这么简单
这个所谓的pattern初看好像似曾相识,就是一个thread pool嘛, 按通常的做法,request可以实现Runnable接口,把要做的事情放在run方法中,由worker去执行,具体实现时还要注意同步的问题
不过,由此我们可以想到Swing的工作方式。Swing是事件驱动的,它有一个the event-dispatch queue,这里之所以用the,是因为这个队列是唯一的,就和上面说的流水线一样。Swing的各个组件相当于客户,不断把各种事件(键盘或者鼠标事件,等等)塞入event queue中,queue有个专门的线程负责把这些事件送给相应的listener,就实现了最基本的事件驱动模型。如果不采用这种模型,即事件由专门线程处理的话,界面的相应速度就很差了
如果有用过Java做游戏的话,应该都接触过javax.swing.SwingUtilities这个类,里面有个invokeAndWait方法,就是用来让其他线程操作Swing组件的。为什么不能直接操作呢,如上所述,event dispatch queue是唯一的,因此Swing组件在设计时就没有过多考虑多线程的问题,反正由event dispatch queue统一操作,这样可以提高速度(尽管Swing本来就很慢),但是当其他线程要操作Swing组件时,就可能有潜在的不稳定因素,所以才有了invokeAndWait方法,调用此方法的线程会wait直到所需操作已经完成
还没说完,再仔细想想,我们在程序里也常常对那些组件直接操作而非用什么invokeAndWait,这里又有一些细节值得注意。首先是在你调用组件的setVisible等方法之前,你是可以随便改组件的,调用完setVisible之后,只有少数方法,比如repaint,addListener等等。最后,根据jdk文档所言,这个方法是用来给应用程序线程改变GUI外观的。如果非要直接改,不一定会出错,多线程本来就是比较难说的,呵呵,我也没试过,改天可以尝试一下。
每 個執行緒(线程)處理一個請求,每次執行緒執行完請求後,再次嘗試取得下一個請求並執行,這是Worker Thread的基本概念,對於一些需要冗長計算或要在背景執行的請求,可以採用Worker Thread。
在 Thread-Per-Message 模式中,其實已經有點Worker Thread的概念,在Service物件接收到資料後,以匿名方式建立執行緒來處理資料,那個建立的執行緒就是Worker Thread,只不用過就丟了。
Worker Thread可以應用在不同的場合,例如在 Guarded Suspension 模式 的範例,是使用一個執行緒來處理請求佇列中的請求,如果請求不斷來到,且請求中可能有冗長的處理,則請求佇列中的請求可能會來不及消化。
您可以為請求佇列中的每個請求配給一個執行緒來處理,不過實際上,只要建立足夠多的執行緒即可,
Worker Thread模式在Request的管理上像是 Producer Consumer 模式,在Request的行为上像是 Command 模式。
Producer Consumer模式专注于Product的生产与消费,至于Product被消费时是作何处理,则不在它的讨论范围之中。

如果您的Product是一个Request,消费者取得Request之后,执行Request中指定的请求方法,也就是使用Command模式,并且您的Request缓冲区还管理了Consumer,就有Worker Thread模式的意思了。

在Sequence Diagram上,可以看出Worker Thread同时展现了Producer Consumer模式与Command模式:

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) {
}
}
public String toString() {
return "[ Request from " + name + " No." + number + " ]";
}
}
ClientThread:
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;
}
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) {
}
}
}
WorkerThread:
public class WorkerThread extends Thread {
private final Channel channel;
public WorkerThread(String name, Channel channel) {
super(name);
this.channel = channel;
}
public void run() {
while (true) {
Request request = channel.takeRequest();
request.execute();
}
}
}
Channel: 可以LinkedList
public class Channel {
private static final int MAX_REQUEST = 100;
private final Request[] requestQueue;
private int tail; // 下一个putRequest的地方
private int head; // 下一个takeRequest的地方
private int count; // Request的数量
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();
}
}
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 Main {
public static void main(String[] args) {
Channel channel = new Channel(5); // 工人线程的數量
channel.startWorkers();
new ClientThread("Alice", channel).start();
new ClientThread("Bobby", channel).start();
new ClientThread("Chris", channel).start();
}
}
参考了:http://www.riabook.cn/doc/designpattern/WorkerThread.htm
http://openhome.cc/Gossip/DesignPattern/WorkerThread.htm
http://chxiaowu.iteye.com/blog/1320767
更多:http://developer.51cto.com/art/201305/395279_1.htm
多线程 Worker Thread 模式的更多相关文章
- 多线程系列之九:Worker Thread模式
一,Worker Thread模式 也叫ThreadPool(线程池模式) 二,示例程序 情景:一个工作车间有多个工人处理请求,客户可以向车间添加请求.请求类:Request定义了请求的信息和处理该请 ...
- Worker Thread模式
工人线程Worker thread会逐个取回工作并进行处理,当所有工作全部完成后,工人线程会等待新的工作到来 5个工人线程从传送带取数据,3个传送工人线程将数据放入传送带 public class C ...
- 多线程程序设计学习(9)worker pattern模式
Worker pattern[工作模式]一:Worker pattern的参与者--->Client(委托人线程)--->Channel(通道,里边有,存放请求的队列)--->Req ...
- 14.多线程设计模式 - Master-Worker模式
多线程设计模式 - Master-Worker模式 并发设计模式属于设计优化的一部分,它对于一些常用的多线程结构的总结和抽象.与串行相比并行程序结构通常较为复杂,因此合理的使用并行模式在多线程并发中更 ...
- reactor模式:多线程的reactor模式
上文说到单线程的reactor模式 reactor模式:单线程的reactor模式 单线程的reactor模式并没有解决IO和CPU处理速度不匹配问题,所以多线程的reactor模式引入线程池的概念, ...
- ios基础篇(二十九)—— 多线程(Thread、Cocoa operations和GCD)
一.进程与线程 1.进程 进程是指在系统中正在运行的一个应用程序,每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内: 如果我们把CPU比作一个工厂,那么进程就好比工厂的车间,一个工厂有 ...
- php Pthread 多线程 Worker
<?php //PHP 高级编程之多线程 http://www.netkiller.cn/journal/thread.php.html#idp57489856 //worker 是一个具有持久 ...
- 多线程设计模式 - Future模式
Future模式是多线程开发中非常常见的一种设计模式,它的核心思想是异步调用.这类似我们日常生活中的在线购物流程,带在购物网看着一件商品时可以提交表单,当订单完成后就可以在家里等待商品送货上门.或者说 ...
- 13.多线程设计模式 - Future模式
多线程设计模式 - Future模式 并发设计模式属于设计优化的一部分,它对于一些常用的多线程结构的总结和抽象.与串行相比并行程序结构通常较为复杂,因此合理的使用并行模式在多线程并发中更具有意义. 1 ...
随机推荐
- c# mongo 返回指定的列
var query= db.GetCollection<Merchant>("merchant").Find(Query<Merchant>.EQ(m =& ...
- 实战:sqlserver 数据实时同步到mysql
1.安装安装mysqlconnector 2.配置mysqlconnector ODBC数据管理器->系统DSN->加入->mysql ODBC 5.3 ANSI driver-&g ...
- [AngularJS] 5 simple ways to speed up your AngularJS application
Nowdays, Single page apps are becoming increasingly popular among the fornt-end developers. It is th ...
- 关于 iOS socket 都在这里了
socket(套接字)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程 ...
- Linux开发工具之Makefile(下)
二.Makefile(下) 01.make常用内嵌函数 函数调用 $(function arguments) $(wildcard PATTERN) 当前目录下匹配模式的文件 例如:src ...
- 【开源java游戏框架libgdx专题】-03-项目开发与调试
创建libgdx项目 下载项目配置工具 gdx-setup.jar 生成项目 导入Eclipse File -> Import -> Gradle -> Gradle Project ...
- windows安装服务
我安装了windows服务的时候监控其他机子的时候,我在调试的时候用的是Account是其他用户是可以正常的,但是安装成服务的时候,老是被拒绝. 后来我将Account改成NetworkService ...
- oracle中使用minus进行数据排除(类似SqlServer except函数)
minus这个集合操作符号的作用是从一个结果集合中减掉另一个结果集中数据,也就是说从一个结果集中去除两个结果集中的共有部分. 下面是一些例子: 这个例子使用minus从第一个结果集中将两个结果集的公有 ...
- Android设备 cocos2dx 骨骼动画注册事件播放音效,退到后台再返回黑屏问题
最近遇到一个cocos2dx 骨骼动画注册事件播放音效,在骨骼动画播放的时候,按HOME键退到桌面,再次打开游戏的时候,会黑屏. 解决办法如下,可能不是太完美,至少解决了大部分问题. 1.在org.c ...
- 关于margin-top失效的解决方法
常出现两种情况:(一)margin-top失效 先看下面代码: <div><div class="box1" >float:left</div> ...