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

  1. 多线程系列之九:Worker Thread模式

    一,Worker Thread模式 也叫ThreadPool(线程池模式) 二,示例程序 情景:一个工作车间有多个工人处理请求,客户可以向车间添加请求.请求类:Request定义了请求的信息和处理该请 ...

  2. Worker Thread模式

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

  3. 多线程程序设计学习(9)worker pattern模式

    Worker pattern[工作模式]一:Worker pattern的参与者--->Client(委托人线程)--->Channel(通道,里边有,存放请求的队列)--->Req ...

  4. 14.多线程设计模式 - Master-Worker模式

    多线程设计模式 - Master-Worker模式 并发设计模式属于设计优化的一部分,它对于一些常用的多线程结构的总结和抽象.与串行相比并行程序结构通常较为复杂,因此合理的使用并行模式在多线程并发中更 ...

  5. reactor模式:多线程的reactor模式

    上文说到单线程的reactor模式 reactor模式:单线程的reactor模式 单线程的reactor模式并没有解决IO和CPU处理速度不匹配问题,所以多线程的reactor模式引入线程池的概念, ...

  6. ios基础篇(二十九)—— 多线程(Thread、Cocoa operations和GCD)

    一.进程与线程 1.进程 进程是指在系统中正在运行的一个应用程序,每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内: 如果我们把CPU比作一个工厂,那么进程就好比工厂的车间,一个工厂有 ...

  7. php Pthread 多线程 Worker

    <?php //PHP 高级编程之多线程 http://www.netkiller.cn/journal/thread.php.html#idp57489856 //worker 是一个具有持久 ...

  8. 多线程设计模式 - Future模式

    Future模式是多线程开发中非常常见的一种设计模式,它的核心思想是异步调用.这类似我们日常生活中的在线购物流程,带在购物网看着一件商品时可以提交表单,当订单完成后就可以在家里等待商品送货上门.或者说 ...

  9. 13.多线程设计模式 - Future模式

    多线程设计模式 - Future模式 并发设计模式属于设计优化的一部分,它对于一些常用的多线程结构的总结和抽象.与串行相比并行程序结构通常较为复杂,因此合理的使用并行模式在多线程并发中更具有意义. 1 ...

随机推荐

  1. angular ng-class使用笔记

    在前面Angularjs开发一些经验总结中说到在angular开发中angular controller never 包含DOM元素(html/css),在controller需要一个简单的POJO( ...

  2. 2015 UESTC Winter Training #10【Northeastern Europe 2009】

    2015 UESTC Winter Training #10 Northeastern Europe 2009 最近集训都不在状态啊,嘛,上午一直在练车,比赛时也是刚吃过午饭,状态不好也难免,下次比赛 ...

  3. js正则表达式验证大全

    /判断输入内容是否为空    function IsNull(){        var str = document.getElementById('str').value.trim();      ...

  4. vertical-align各属性对比

    测试用代码 <!DOCTYPE html> <html> <head> <style> #dd { //line-height: 300px; back ...

  5. vedeo与audio标签的使用

    浏览器原生支持音视频无疑是一件大事——尤其对移动设备而言.不依赖Flash,意味着更加省电.安全和快速的播放体验,而且只需要引入一个标签,就能播放自如. <video src="dao ...

  6. (多对象)Json转换成List

    写的不好,请大家见谅. 1.Json 格式{"packages":[{“type”:”aaa”}],"zone_packages":[{"ticket ...

  7. 用JAVA给JSON进行排版

    之前听到朋友的面试题,是如何对JSON进行排版,于是就写了一个Demo,觉得挺有意思的,就贴出来了. 这个就是记录缩进来输出,大家也可以尝试一下其他更好算法来进行输出. 功能:可以把一行的JSON字符 ...

  8. AfxMessageBox("这里为提示框的内容");程序弹出一个提示窗口,可以做调试提示信息

    AfxMessageBox("这里为提示框的内容"); 同时AfxMessageBox(AFX_IDP_PARSE_INT);里面也可以系统宏定义的一些参数

  9. Bit Map解析

    1. Bit Map算法简介 来自于<编程珠玑>.所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素.由于采用了Bit为单位来存储数据,因此在存储空 ...

  10. 使用C#连接ORACLE数据库

    一.使用OracleClient组件连接Oracle   .Net框架的System.Data.OracleClient.dll组件(ADO.Net组件),为连接和使用Oracle数据库提供了很大的方 ...