参考:《Netty权威指南》
由于 一请求一线程 的I/O模型,在高并发时创建大量的线程,严重降低系统性能,并且容易造成线程堆栈溢出等问题。
采用线程池和消息队列的“伪异步”模型,是一种改良版的模型。
原理:当有新的客户端请求到来时,将socket封装成一个Task(该任务实现了Runnable接口),投递到线程池中进行处理。
而线程池始终维护一个消息队列和N个活跃着的线程,这些线程被分配,对消息队列中的Task进行处理。
由于线程池可以设置消息队列的大小和线程的数量,因此它的资源占用是人为可控的,不会导致资源耗尽和宕机。
缺点:底层通信仍然采用同步阻塞I/O模型,因此无法从根本上解决高并发的问题。
采用线程池和消息队列的“伪异步”I/O模型 实现TimeServer
(1)TimeServerHandlerExecutePool.java
package com.tao.netty.waio;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 处理TimeServer连接任务的线程池
* 内部有消息队列
* @author Tao
*
*/
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.tao.netty.waio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Date;
/**
* 处理客户端请求的类
* @author Tao
*
*/
public class TimeServerHandler implements Runnable{
private Socket socket;
public TimeServerHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader in = null;
PrintWriter out = null;
try {
//在socket上建立输入输出
in = new BufferedReader(new InputStreamReader(this.socket.getInputStream(), "utf-8"));
out = new PrintWriter(this.socket.getOutputStream(), true);
String currentTime = null;
String body = null;
while(true) {
body = in.readLine();//读入一行
if(body == null) {
break;
}
System.out.println("TimeServer收到消息:" + body);
//如果收到请求时间的命令则返回当前时间
if("order:current time".equalsIgnoreCase(body)) {
currentTime = new Date(System.currentTimeMillis()).toString();
}else {
currentTime = "无效的命令";
}
out.println(currentTime);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(in != null) {
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(out != null) {
out.close();
out = null;
}
if(this.socket != null) {
try {
this.socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.socket = null;
}
}
}
}
package com.tao.netty.waio;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
*
* @author Tao
*
* 同步阻塞式I/O创建的TimeServer 服务端
*/
public class TimeServer {
public static void main(String[] args) throws IOException {
int port = 8080; //默认端口号8080
if(args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]); //指定端口号
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
ServerSocket server = null; //服务器socket
try {
server = new ServerSocket(port);
System.out.println("TimeServer启动了,端口号是" + port);
Socket socket = null;
//创建I/O任务线程池,指定最大线程个数为50,消息队列长度为10000
TimeServerHandlerExecutePool singleExecutor = new TimeServerHandlerExecutePool(50, 10000);
//监听客户端请求
while(true) {
socket = server.accept(); //客户端请求到来
singleExecutor.execute(new TimeServerHandler(socket)); //交给线程池处理请求
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(server != null) {
System.out.println("关闭TimeServer");
server.close();
server = null;
}
}
}
}
package com.tao.netty.waio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
/**
*
* @author Tao
*
* 客户端
*/
public class TimeClient {
public static void main(String[] args) throws IOException {
int port = 8080;
if(args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
Socket socket = null;
BufferedReader in = null;
PrintWriter out = null;
Scanner scanner = null;
try {
socket = new Socket("127.0.0.1", port);//连接服务器
in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
out = new PrintWriter(socket.getOutputStream(), true);
scanner = new Scanner(System.in);
while(true) {
String line = scanner.nextLine();
if(line.equalsIgnoreCase("exit")) {
break;
}
out.println(line);
String receive = in.readLine();
System.out.println("收到服务器的响应:" + receive);
}
} catch (Exception e) {
// TODO: handle exception
} finally {
if(scanner != null) {
scanner.close();
}
if(in != null) {
in.close();
}
if(out != null) {
out.close();
}
}
}
}
下一节介绍Java NIO编程,真正的 非阻塞I/O