伪异步I/O编程及代码实现

伪异步I/O编程

    为了改进这种一连接一线程的模型,我们可以使用线程池来管理这些线程(需要了解更多请参考前面提供的文章),实现1个或多个线程处理N个客户端的模型(但是底层还是使用的同步阻塞I/O),通常被称为“伪异步I/O模型“。

    伪异步I/O模型图:

    02

    实现很简单,我们只需要将新建线程的地方,交给线程池管理即可,只需要改动刚刚的Server代码即可:

[java] view plain copy
 print?
  1. package com.anxpp.io.calculator.bio;  
  2. import java.io.IOException;  
  3. import java.net.ServerSocket;  
  4. import java.net.Socket;  
  5. import java.util.concurrent.ExecutorService;  
  6. import java.util.concurrent.Executors;  
  7. /** 
  8.  * BIO服务端源码__伪异步I/O 
  9.  * @author yangtao__anxpp.com 
  10.  * @version 1.0 
  11.  */  
  12. public final class ServerBetter {  
  13.     //默认的端口号  
  14.     private static int DEFAULT_PORT = 12345;  
  15.     //单例的ServerSocket  
  16.     private static ServerSocket server;  
  17.     //线程池 懒汉式的单例  
  18.     private static ExecutorService executorService = Executors.newFixedThreadPool(60);  
  19.     //根据传入参数设置监听端口,如果没有参数调用以下方法并使用默认值  
  20.     public static void start() throws IOException{  
  21.         //使用默认值  
  22.         start(DEFAULT_PORT);  
  23.     }  
  24.     //这个方法不会被大量并发访问,不太需要考虑效率,直接进行方法同步就行了  
  25.     public synchronized static void start(int port) throws IOException{  
  26.         if(server != nullreturn;  
  27.         try{  
  28.             //通过构造函数创建ServerSocket  
  29.             //如果端口合法且空闲,服务端就监听成功  
  30.             server = new ServerSocket(port);  
  31.             System.out.println("服务器已启动,端口号:" + port);  
  32.             //通过无线循环监听客户端连接  
  33.             //如果没有客户端接入,将阻塞在accept操作上。  
  34.             while(true){  
  35.                 Socket socket = server.accept();  
  36.                 //当有新的客户端接入时,会执行下面的代码  
  37.                 //然后创建一个新的线程处理这条Socket链路  
  38.                 executorService.execute(new ServerHandler(socket));  
  39.             }  
  40.         }finally{  
  41.             //一些必要的清理工作  
  42.             if(server != null){  
  43.                 System.out.println("服务器已关闭。");  
  44.                 server.close();  
  45.                 server = null;  
  46.             }  
  47.         }  
  48.     }  
  49. }  

    测试运行结果是一样的。

    我们知道,如果使用CachedThreadPool线程池(不限制线程数量,如果不清楚请参考文首提供的文章),其实除了能自动帮我们管理线程(复用),看起来也就像是1:1的客户端:线程数模型,而使用FixedThreadPool我们就有效的控制了线程的最大数量,保证了系统有限的资源的控制,实现了N:M的伪异步I/O模型。

    但是,正因为限制了线程数量,如果发生大量并发请求,超过最大数量的线程就只能等待,直到线程池中的有空闲的线程可以被复用。而对Socket的输入流就行读取时,会一直阻塞,直到发生:

  •     有数据可读
  •     可用数据以及读取完毕
  •     发生空指针或I/O异常

    所以在读取数据较慢时(比如数据量大、网络传输慢等),大量并发的情况下,其他接入的消息,只能一直等待,这就是最大的弊端。

    而后面即将介绍的NIO,就能解决这个难题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值