java 线程 设计模式_Java多线程设计模式(3)

《Java多线程设计模式》读书笔记3

目录:

1 Thread-Per-Message Pattern

2 Worker Thread Pattern

3 Future Pattern

===================Thread-Per-Message Pattern===============

Thread per message,每个消息一个线程。Message 在这里可以看作是“命令”或“请求”的意思。对每个命令或请求,分配一个线程,有这个线程执行工作,这就是Thread-Per-Message Pattern。

Thread-Per-Message Pattern的适用场合:

1. 适合在操作顺序无所谓时使用。

2. 在不需要返回值的时候。

3. 可以应用在服务器的制作上,提升响应性,降低延迟时间。

进程和线程

1 进程和线程最大的差异在于内存能否共享。

通常每个进程所拥有的内存空间是各自独立的。进程不能擅自读取,改写其他进程的内存空间。因为进程的内存空间是相互独立的,所以进程无需担心被其他进程破坏的危险。而线程则是共享内存的。

2 进程和线程另一个差异,在于context-switch的频繁程度。

进程切换需要存储和保留的信息比较多,所以切换需要花费一些时间。然而线程需要管理的context信息比进程要少得多,所以一般而言线程context-switch比进程的context-switch要快的多。

===================Worker Thread Pattern===============

线程池机制 主要解决每次请求都要建立新线程的成本。事先启动用来执行工作的线程(工人线程)备用。并使用Producer-Consumer Pattern,将表示工作内容的实例传递给工人线程。这么一来,工人线程会负责执行工作,就不需要一直启动新的线程了。

实现:

工作区(核心)

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[i] = new WorkerThread("Worker-" + i, this);

}

}

//工作线程开始工作

public void startWorkers() {

for (int i = 0; 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 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 + " ]";

}

}

工作线程

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();

}

}

}

放入请求线程

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) {

}

}

}

测试类

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();

}

}

===================Future Pattern===============

Future是“未来”,“期货”的意思。假设有一个执行起来需要花一些时间的方法,我们就不要等待执行结果出来了,而获取一张替的“提货单”。因为获取提货单不需要花时间,这时这个“提货单”就是Future参与者。获取Future参与者的线程,会在事后再去获取执行结果。就好像那提货单去领取蛋糕一样,如果已经有执行结果了,就可以马上拿到数据。如果执行结果还没好,则继续等待到执行结果出现为止。

Thread-Per-Message Pattern是将花费时间的工作交给别的线程,以提高程序的响应性。不过,如果我们需要得到别的线程所处理的结果时,就行不通了。若同步执行需要花一些时间的操作,会使程序响应性降低。但是,如果异步的开始执行,却无法在第一时间得知结果。这种时候就要使用Future Pattern。首先我们建立一个与处理结果具有相同接口(API)的Future参与者。接着,在开始处理时,先把Future参与者当作返回值返回。直到其他线程处理完以后,才将真正的结果设置给Future参与者。Client参与者可以通过Future参与者得到处理的结果。使用这个Pattern,可使响应性不降低,并得到想要的处理结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值