对JAVA NIO的使用心得

之前接触过一个项目,是tcp/ip对门禁上位机的数据监听,开始使用的是传统的Bio方式,但是由于ip数量过多,经常会出现socket连接No buffer space available的问题,导致接口大面积调用(webservice,httpclient)失败的问题,重启服务器后又恢复了正常。报错如下Caused by: java.net.SocketException: No buffer space available (maximum connections reached?): connect。后来改进使用队列的方式,发现还是坚持不了多长时间,又会出现同样的报错。后来想到用NIO,原因是nio的机制是同步非阻塞,适用于连接数目多且连接比较短(轻操作)的架构。

先来对BIO、NIO、AIO做比较:

BIO(IO)
同步阻塞,传统io方式。
适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中。
NIO
同步非阻塞,jdk4开始支持。
适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器。
AIO
异步非阻塞,jdk7开始支持。
适用于连接数目多且连接比较长(重操作)的架构。
形象的理解NIO和AIO:如果把内核比作点外卖,NIO就是你要自己时不时查下外卖是否已经到了你楼下,然后自己去取快递;AIO就是外卖员送餐上门了。


项目代码如下:

public boolean processData() throws Exception {
   logger.info("processData....Start...");

   initQueue();

   logger.info("开始selector绑定");

   Thread t = new Thread(new Runnable() {
      @Override
      public void run() {

         Selector selector = null;
         try {
            selector = Selector.open();

            for (String serverIP : ipSet) {

               
               SocketChannel sChannel = createSocketChannel(serverIP, 8000);
               //将通道注册到一个选择器上(非阻塞模式与选择器搭配会工作的更好) validOps:返回一个操作集,标识此通道所支持的操作。
               //将通道管理器与通道绑定,并为该通道注册SelectionKey.validOps事件
               SelectionKey key = sChannel.register(selector, sChannel.validOps());
               System.out.println("CreateSocketChannel ip:" + serverIP + " SelectionKey:" + key);
               //SocketChannelSelector注册事件句柄存入map
               selKeyMap.put(key, serverIP);

               
            }

            logger.info("processData....End...");

            // 等待事件的循环
            while (true) {
               logger.info("loading...");
               try {
                  // 等待 阻塞到至少有一个通道在注册的事件上就绪了
                  selector.select();
               } catch (IOException e) {
                  logger.error("select异常 ");
                  e.printStackTrace();
               }
               // 所有事件列表 遍历selectionKey来访问就绪的通道
               Iterator<SelectionKey> it = selector.selectedKeys().iterator();
               // 处理每一个事件
               while (it.hasNext()) {
                  // 得到关键字
                  SelectionKey selKey = it.next();
                  // 删除已经处理的关键字
                  try {
                     // 处理事件
                     processSelectionKey(selKey);
                  } catch (IOException e) {
                     // 处理异常
                     // selKey.cancel();
                     logger.error("处理异常,key:" + selKeyMap.get(selKey));
                     e.printStackTrace();
                  }
                  //删除已选key,防止重复处理
                  it.remove();

                  
               }

               // 线程睡眠1秒钟
               try {
                  Thread.sleep(1000);
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
            }

            

         } catch (IOException e) {
            e.printStackTrace();
         } finally {
            try {
               if (selector != null) {
                  selector.close();
               }
               // if (ssc != null) {
               // ssc.close();
               // }
            } catch (IOException e) {
               e.printStackTrace();
            }
         }

      }
   });
   t.setDaemon(true);
   t.start();

   // 跟门禁控制器的心跳
   Timer heartBeatTimer = new Timer();
   TimerTask heartBeatTimerTask = new TimerTask() {
      @Override
      public void run() {
         logger.info("heartBeatTimerTask timer");
         logger.info("selKeyMap size is " + selKeyMap.size());
         for (SelectionKey key : selKeyMap.keySet()) {
            try {
               
               SocketChannel channel = (SocketChannel) key.channel();
               heartBeat.clear();
               byte value = (byte)0x7e;
               heartBeat.put(value);
               heartBeat.put(value);
               heartBeat.flip();
               if (key.isValid() && key.isWritable()) {
                  channel.write(heartBeat);
               }                 
            }
            catch (Exception e) {
               logger.info(e.getMessage());
               e.printStackTrace();
            }
         }
      }
   };
   // 每隔10秒发一次心跳数据
   heartBeatTimer.schedule(heartBeatTimerTask, 10000, 10000);
   
   

   return true;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值