同步阻塞I/O也就是一个客户端请求,服务端需要开启一个线程处理,无法满足高并发需求。后来前辈对这种线程模型进行了优化--服务端通过一个线程池来处理多个客户端的请求接入,形成客户端个数M:线程池最大线程数N的比例关系,其中M可以远远大于N。通过线程池客户灵活地调配线程资源,设置线程的最大值,防止由于海量并发接入导致线程耗尽。
采用线程池和任务队列可以实现一种伪异步的I/O通信模型
下面通过一个例子来演示
package com.hueason.netty.n1.tpio;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by Administrator on 2017/4/18.
*/
public class TimeServer {
public static void main(String[] args) throws IOException {
int port = 8080;
if (args != null && args.length > 0) {
port = Integer.valueOf(args[0]);
}
ServerSocket server = null;
try {
server = new ServerSocket(port);
System.out.println("The time server is start in port :" + port);
Socket socket = null;
//创建I/O任务线程池
TimeServerHandlerExecutePool singleExecutor = new TimeServerHandlerExecutePool(50, 10000);
while (true) {
socket = server.accept();
singleExecutor.execute(new TimeServerHandler(socket));
}
}finally {
if(server != null){
System.out.println("The time server close");
server.close();
server = null;
}
}
}
}
package com.hueason.netty.n1.tpio;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by Administrator on 2017/4/18.
*/
public class TimeServerHandlerExecutePool {
private ExecutorService executor;
public TimeServerHandlerExecutePool(int maxPoolSize, int queueSize) {
executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),maxPoolSize,120L, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(queueSize));
}
public void execute(Runnable task) {
executor.execute(task);
}
}
客户端
package com.hueason.netty.n1.tpio;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by Administrator on 2017/4/18.
*/
public class TimeServer {
public static void main(String[] args) throws IOException {
int port = 8080;
if (args != null && args.length > 0) {
port = Integer.valueOf(args[0]);
}
ServerSocket server = null;
try {
server = new ServerSocket(port);
System.out.println("The time server is start in port :" + port);
Socket socket = null;
//创建I/O任务线程池
TimeServerHandlerExecutePool singleExecutor = new TimeServerHandlerExecutePool(50, 10000);
while (true) {
socket = server.accept();
singleExecutor.execute(new TimeServerHandler(socket));
}
}finally {
if(server != null){
System.out.println("The time server close");
server.close();
server = null;
}
}
}
}
如Server中所示,当新的客户端接入时,将客户端的Socket封装成一个Taskt投递到线程池中进行处理,此处使用的是JDK自带的线程池,线程池维护这一个消息队列和N个活跃线程,对消息队列总的任务进行处理。
伪异步的优势:由于线程池客户设置消息队列的大小和最大线程数,因此,它的资源占用是可控的,无论多少个客户端并发访问,都不会导致资源的耗尽和宕机。
弊端:底层Socket的读和写操作都还是同步阻塞的,阻塞的时间取决于客户端I/O线程的处理速度和网络I/O的传输速度。由于在生产环境中这两项都无法绝对保证,所以系统的可靠性不高。
伪异步I/O仅仅是对BIO线程模型的一个简单优化,无法从根本上解决同步I/O导致的通信线程阻塞问题。