Thread Per Message 直译过来就是“每个消息一个线程”的意思。Message 在这里可以理解为“命令”或
“请求”。未每个命令或请求重新分配一个线程,由这个线程来执行处理-这就是Thread-Per-Message模式。
在Thread-Per-Message 模式种,消息的“委托端”和“执行端”时不同线程,消息的委托端线程会告诉执行
端线程“这项工作就交给你了”
类说明
名字 | 说明 |
Main | 向Host发送字符显示请求的类 |
Host | 针对请求创建线程的类 |
Helper | 提供字符显示功能的被动类 |
类图示例:
代码示例(Thread):
package pattern.ThreadPerMessage.Sample;
/**
* 创建一个Host实例,然后调用Host的request方法
*/
public class Main {
public static void main(String[] args) {
System.out.println("main BEGIN");
Host host = new Host();
host.request(10, 'A');
host.request(20, 'B');
host.request(30, 'C');
System.out.println("main END");
}
}
package pattern.ThreadPerMessage.Sample;
public class Host {
private final Helper helper = new Helper();
/**
* request方法新启动一个线程。实际操作由该线程来执行
* @param count
* @param c
*/
public void request(final int count, final char c) {
System.out.println(" request(" + count + ", " + c + ") BEGIN");
new Thread() {
public void run() {
helper.handle(count, c);
}
}.start();
System.out.println(" request(" + count + ", " + c + ") END");
}
}
package pattern.ThreadPerMessage.Sample;
/**
* Helper 类提供了一个用于按指定次数显示字符的handle方法
*/
public class Helper {
public void handle(int count, char c) {
System.out.println(" handle(" + count + ", " + c + ") BEGIN");
for (int i = 0; i < count; i++) {
slowly();
System.out.print(c);
}
System.out.println("");
System.out.println(" handle(" + count + ", " + c + ") END");
}
private void slowly() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
Thread-Per-Message 模式的七种实现方式的示例:
-
java.lang.Thread 类 最基本的创建、启动线程的类
-
java.lang.Runnable 接口 表示线程所执行“工作”的接口
-
java.util.concurrent.ThreadFactory 接口 将线程创建抽象化了的接口
-
Java.util.concurrent.Executor接口 将线程执行抽象化了的接口
-
java.util.concurrent.ExecutorService 接口 将被复用的线程抽象化了的接口
-
java.util.concurrent.ScheduledExecutorService 接口 将被调度的线程的执行抽象化了的接口
-
Java.util.concurrent.Executors 类 用于创建实例的工具类
场景案例:
web服务器以1秒的间隔从10到0进行倒计时的Web服务器,该服务器是单线程运行的,同时只能响应一个Web浏览器。在一个浏览器进行倒计时的约10秒这个期间内,其他浏览器都要进行等待。
代码示例:
package pattern.ThreadPerMessage.WebServer;
import java.io.IOException;
public class Main {
public static void main(String args[]) {
try {
new MiniServer(8888).execute();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package pattern.ThreadPerMessage.WebServer;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class MiniServer {
private final int portnumber;
public MiniServer(int portnumber) {
this.portnumber = portnumber;
}
public void execute() throws IOException {
ServerSocket serverSocket = new ServerSocket(portnumber);
System.out.println("Listening on " + serverSocket);
try {
while (true) {
System.out.println("Accepting...");
Socket clientSocket = serverSocket.accept();
System.out.println("Connected to " + clientSocket);
try {
//这一段执行时会阻塞式执行
Service.service(clientSocket);
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
serverSocket.close();
}
}
}
package pattern.ThreadPerMessage.WebServer;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class Service {
private Service() {
}
public static void service(Socket clientSocket) throws IOException {
System.out.println(Thread.currentThread().getName() + ": Service.service(" + clientSocket + ") BEGIN");
try {
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
out.writeBytes("HTTP/1.0 200 OK\r\n");
out.writeBytes("Content-type: text/html\r\n");
out.writeBytes("\r\n");
out.writeBytes("<html><head><title>Countdown</title></head><body>");
out.writeBytes("<h1>Countdown start!</h1>");
for (int i = 10; i >= 0; i--) {
System.out.println(Thread.currentThread().getName() + ": Countdown i = " + i);
out.writeBytes("<h1>" + i + "</h1>");
out.flush();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
out.writeBytes("</body></html>");
} finally {
clientSocket.close();
}
System.out.println(Thread.currentThread().getName() + ": Service.service(" + clientSocket + ") END");
}
}
使用Thread-Per-Message 模式进行代码改造:
package pattern.ThreadPerMessage.WebServer;
import java.io.IOException;
public class Main {
public static void main(String args[]) {
try {
new MiniServer(8888).execute();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package pattern.ThreadPerMessage.WebServer;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MiniServer {
private final int portnumber;
public MiniServer(int portnumber) {
this.portnumber = portnumber;
}
public void execute() throws IOException {
ServerSocket serverSocket = new ServerSocket(portnumber);
ExecutorService executorService = Executors.newCachedThreadPool();
System.out.println("Listening on " + serverSocket);
try {
while (true) {
System.out.println("Accepting...");
final Socket clientSocket = serverSocket.accept();
System.out.println("Connected to " + clientSocket);
executorService.execute(
new Runnable() {
public void run() {
try {
Service.service(clientSocket);
} catch (IOException e) {
e.printStackTrace();
}
}
}
);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
serverSocket.close();
}
}
}
package pattern.ThreadPerMessage.WebServer;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class Service {
private Service() {
}
public static void service(Socket clientSocket) throws IOException {
System.out.println(Thread.currentThread().getName() + ": Service.service(" + clientSocket + ") BEGIN");
try {
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
out.writeBytes("HTTP/1.0 200 OK\r\n");
out.writeBytes("Content-type: text/html\r\n");
out.writeBytes("\r\n");
out.writeBytes("<html><head><title>Countdown</title></head><body>");
out.writeBytes("<h1>Countdown start!</h1>");
for (int i = 10; i >= 0; i--) {
System.out.println(Thread.currentThread().getName() + ": Countdown i = " + i);
out.writeBytes("<h1>" + i + "</h1>");
out.flush();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
out.writeBytes("</body></html>");
} finally {
clientSocket.close();
}
System.out.println(Thread.currentThread().getName() + ": Service.service(" + clientSocket + ") END");
}
}