2.2.2 伪异步式I/O创建的TimeServer源码分析
我们对服务端代码进行一些改造,代码如下。
代码清单2-4 伪异步I/O的TimeServer
- 13. public class TimeServer {
- 14.
- 15. /**
- 16. * @param args
- 17. * @throws IOException
- 18. */
- 19. public static void main(String[] args) throws IOException {
- 20. int port = 8080;
- 21. if (args != null && args.length > 0) {
- 22. try {
- 23. port = Integer.valueOf(args[0]);
- 24. } catch (NumberFormatException e) {
- 25. // 采用默认值
- 26. }
- 27. }
- 28. ServerSocket server = null;
- 29. try {
- 30. server = new ServerSocket(port);
- 31. System.out.println("The time server is start in port : " + port);
- 32. Socket socket = null;
- 33. TimeServerHandlerExecutePool singleExecutor = new TimeServerHandlerExecutePool(
- 34. 50, 10000);// 创建I/O任务线程池
- 35. while (true) {
- 36. socket = server.accept();
- 37. singleExecutor.execute(new TimeServerHandler(socket));
- 38. }
- 39. } finally {
- 40. if (server != null) {
- 41. System.out.println("The time server close");
- 42. server.close();
- 43. server = null;
- 44. }
- 45. }
- 46. }
- 47. }
伪异步I/O的主函数代码发生了变化,我们首先创建一个时间服务器处理类的线程池,当接收到新的客户端连接的时候,将请求Socket封装成一个Task,然后调用线程池的execute方法执行,从而避免了每个请求接入都创建一个新的线程。
代码清单2-5 伪异步I/O的TimeServerHandlerExecutePool
- 12. public class TimeServerHandlerExecutePool {
- 13.
- 14. private ExecutorService executor;
- 15.
- 16. public TimeServerHandlerExecutePool(int maxPoolSize, int queueSize) {
- 17. executor = new ThreadPoolExecutor(Runtime.getRuntime()
- 18. .availableProcessors(), maxPoolSize, 120L, TimeUnit.SECONDS,
- 19. new ArrayBlockingQueue<java.lang.Runnable>(queueSize));
- 20. }
- 21. public void execute(java.lang.Runnable task) {
- 22. executor.execute(task);
- 23. }
- 24. }
由于线程池和消息队列都是有界的,因此,无论客户端并发连接数多大,它都不会导致线程个数过于膨胀或者内存溢出,相比于传统的一连接一线程模型,是一种改良。
由于客户端代码并没有改变,因此,我们直接运行服务端和客户端,执行结果如下。
服务端运行结果如图2-6所示。

客户端运行结果如图2-7所示。

伪异步I/O通信框架采用了线程池实现,因此避免了为每个请求都创建一个独立线程造成的线程资源耗尽问题。但是由于它底层的通信依然采用同步阻塞模型,因此无法从根本上解决问题。下个小节我们对伪异步I/O进行深入分析,找到它的弊端,然后看看NIO是如何从根本上解决这个问题的。
喜欢的朋友可以添加我们的微信账号:
51CTO读书频道二维码

51CTO读书频道活动讨论群:342347198