采用线程池和消息队列的“伪异步”I/O模型

参考:《Netty权威指南》


由于 一请求一线程 的I/O模型,在高并发时创建大量的线程,严重降低系统性能,并且容易造成线程堆栈溢出等问题。

采用线程池和消息队列的“伪异步”模型,是一种改良版的模型。

原理:当有新的客户端请求到来时,将socket封装成一个Task(该任务实现了Runnable接口),投递到线程池中进行处理。

          而线程池始终维护一个消息队列和N个活跃着的线程,这些线程被分配,对消息队列中的Task进行处理。

          由于线程池可以设置消息队列的大小和线程的数量,因此它的资源占用是人为可控的,不会导致资源耗尽和宕机。

缺点:底层通信仍然采用同步阻塞I/O模型,因此无法从根本上解决高并发的问题。

采用线程池和消息队列的“伪异步”I/O模型_第1张图片


采用线程池和消息队列的“伪异步”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(queueSize));
	}
	
	//执行任务
	public void execute(Runnable task) {
		executor.execute(task);
	}	
}


(2)TimeServerHandler.java

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;
			}
		}	
	}
}


(3)TimeServer.java

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;
			}
		}	
	}	
}


(4)TimeClient.java

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


你可能感兴趣的:(Java,NIO编程(Netty框架))