结构化并发应用程序
至此,第一部分已经学习完毕,从此篇开始,将进行本书第二部分的学习
在线程中执行任务
- 将一个复杂的任务拆分为多个任务,并为每个任务开启一个线程。
- 需要确定任务边界
- 理想状态下,任务之间是相互独立的。
- 例如大多数服务器应用程序,以用户请求为任务边界,每个请求之间互不影响。
串行的执行任务
- 模拟一个接受用户请求的服务器
- 假设有一万个请求,而我们的服务器,
socket.accept()
,每循环一次才能处理一个请求,也就是说 着一万个请求是按顺序处理的。 - 如果
handleRequest()
还是个阻塞的方法,并发性可想而知。 - 见代码
package net.jcip.examples;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* SingleThreadWebServer
* <p/>
* Sequential web server
*
* @author Brian Goetz and Tim Peierls
*/
public class SingleThreadWebServer {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(80);
while (true) {
Socket connection = socket.accept();
handleRequest(connection);
}
}
private static void handleRequest(Socket connection) {
// request-handling logic here
}
}
显示的为任务创建线程
- 将主要的任务工作量,从主线程中分离出来,主线程只负责响应用户请求,至于请求需要做的任务,由开启的子线程处理。
- 代码如下
- 缺点,为每一个请求创建一个线程,如果没有上限控制的话,在超过服务器的吞吐率之后,服务器被拖垮。
package net.jcip.examples;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* ThreadPerTaskWebServer
* <p/>
* Web server that starts a new thread for each request
*
* @author Brian Goetz and Tim Peierls
*/
public class ThreadPerTaskWebServer {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(80);
while (true) {
final Socket connection = socket.accept();
Runnable task = new Runnable() {
public void run() {
handleRequest(connection);
}
};
new Thread(task).start();
}
}
private static void handleRequest(Socket connection) {
// request-handling logic here
}
}
无线创建线程的不足
- 创建和销毁线程的开销非常高。
- 活跃的线程会消耗资源