`
zhoushijun
  • 浏览: 270363 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

NIO中几个非常重要的技术点

    博客分类:
  • java
阅读更多

这些都是在实践中踩过雷的,今天某应用再次踩雷,把遇到的几个雷都收集一下,给后来者参考。

1.即使是accept事件,没有真正的read和write,Channel也要关闭,否则unix domain socket会被泄漏(WINDOWS更可怕),因为NIO的每个

Channel上都有两个FD用来监听事件(接收和发送走不同的FD)。

2.cancel事件导致CPU占用100%,http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6403933 

其原因就是调用key.cancel()时底层在下一次seelect前并没有真正的取消。导致等待select事件返回却又没有返回我们注册的key.这个事件不断地

循环触发,CPU一直处理返回 key为0的select()调用。解决方法有两种,一是在key.cancel()后立即selectNow();但是如果是多线程并发操作,有

可能这两行语句中间线程被切换,使得key.cancel()后没有立即执行 selectNow().这在多Selector情况下是可能的。另一种就是jetty处理方式,如果

select()返回0且连续几次出现这样的情况(有事件触发返回,却不是返回我们注册的KEY),就将有效的key重新注册到一个新的selector上。其实

glassfish在处理多次次次次write返回为0的情况时也是这种策略。

 

示例代码:(真实的项目中)

  1. int selectTimeout = connectionConfig.getSelectTimeout();  
  2. int allProcessMaxTime = connectionConfig.getAllProcessMaxTime();  
  3. //selector在实现时有bug,epool底层可能会发送一个错误的信号导致select方法提前返回,但没有  
  4. //返回注册的事件,而且不断循环造成CPU100%  
  5. int slelectZeroCount = 0;  
  6. int maxZeroCount = 20;  
  7. int fixed = 0;  
  8.   
  9. while (selector.isOpen() && selector.keys().size() != 0 && allProcessMaxTime > 0) {  
  10.     long start = System.currentTimeMillis();  
  11.     // 查询看是否有已经准备好的通道,指定超时时间  
  12.     int count = selector.select(selectTimeout);  
  13.   
  14.     if (count == 0) {  
  15.         slelectZeroCount++;  
  16.     } else {  
  17.         slelectZeroCount = 0;  
  18.         //保证是连续的count==0时才将slelectZeroCount++,如果其中有一次返回注册事件测已经正常  
  19.     }  
  20.     if (slelectZeroCount > maxZeroCount && fixed == 0) {  
  21.         //没有尝试修复动作,则先进行修复干预  
  22.         for (SelectionKey key : selector.keys()) {  
  23.             if (key.isValid() && key.interestOps() == 0) {  
  24.                 key.cancel();  
  25.             }  
  26.         }  
  27.         fixed = 1;  
  28.     } else if (slelectZeroCount > maxZeroCount && fixed == 1) {  
  29.         //如果已经干预过仍然连续返回0,注意如果不返回0的话slelectZeroCount就被置0.  
  30.         //重新获取一个selector,将当前事件重新注册到新的selector上。并销毁当前selector  
  31.         Selector newSelector = this.getSelector();  
  32.         this.changeSelector(selector, newSelector);  
  33.         selector = newSelector;  
  34.     }  
  35.     //对channel进行正常处理  


重新注册的代码:

  1. private synchronized void changeSelector(Selector oldSelector, Selector newSelector) {  
  2.         for (SelectionKey key : oldSelector.keys()) {  
  3.             if (!key.isValid() || key.interestOps() == 0) {  
  4.                 continue;  
  5.             }  
  6.             Object att = key.attachment();  
  7.             try {  
  8.                 if (att == null) {  
  9.                     key.channel().register(newSelector, key.interestOps());  
  10.                 } else {  
  11.                     key.channel().register(newSelector, key.interestOps(), att);  
  12.                 }  
  13.             } catch (ClosedChannelException e) {  
  14.                 SocketChannel sc = (SocketChannel) key.channel();  
  15.                 sc.close();  
  16.             }  
  17.         }  
  18.         try {  
  19.             oldSelector.close();  
  20.         } catch (IOException e) {  
  21.             logger.error(e.getMessage());  
  22.         }  
  23.   
  24.     }  


同样对于网络状态不好时,连续写操作返回0的处理:

  1. private void flushData(Selector selector, SocketChannel socketChannel, ByteBuffer byteBuffer)  
  2.         throws IOException {  
  3.   
  4.     int count = 0;  
  5.     int maxCount = 20;  
  6.   
  7.     while (byteBuffer.hasRemaining()) {  
  8.         int len = socketChannel.write(byteBuffer);  
  9.         if (len < 0) {  
  10.             throw new EOFException("write channel is closed.");  
  11.         }  
  12.         // 如果不对len==0(即当前网络不可用)的情况处理,则while(byteBuffer.hasRemaining())可能一直  
  13.         // 循环下去而消耗大量的CPU.  
  14.         if (len == 0) {  
  15.             count++;  
  16.         } else {  
  17.             count = 0;  
  18.         }  
  19.         if (count > maxCount) {  
  20.             throw new IOException("can't connect to target.");  
  21.         }  
  22.     }  
  23.   

分享到:
评论

相关推荐

    网络与nio

    通常,NIO的核心包括以下几个部分: 1. **通道(Channels)**:通道是数据传输的途径,它可以读取或写入数据,如SocketChannel、FileChannel等。 2. **缓冲区(Buffers)**:缓冲区是存储数据的地方,所有从通道...

    Java NIO Socket基本

    在Java NIO中,核心组件包括以下几个: 1. **通道(Channel)**:类似于流,但支持双向数据传输。常见的通道类有FileChannel、SocketChannel和ServerSocketChannel等。它们都是`java.nio.channels.Channel`接口的...

    Java NIO Ron Hitchens著

    书中可能涵盖以下几个关键知识点: 1. **通道(Channels)**:NIO中的通道类似于传统IO中的流,但它们可以同时读写数据,并且是非阻塞的。例如,FileChannel用于文件操作,SocketChannel用于网络通信。 2. **缓冲...

    ibm的nio教程

    标题 "IBM的NIO教程" 暗示了我们即将探讨的是Java编程中的非阻塞I/O(Non-blocking Input/Output)技术,特别是在IBM平台上如何使用。NIO是Java平台中用于替代传统I/O(BIO)的一种机制,它允许程序在等待数据传输时...

    Java NIO 在并发型服务器设计中的应用

    使用NIO设计并发型服务器程序的过程主要包括以下几个步骤: 1. **初始化Selector**:创建一个Selector实例作为监控通道的状态变化的控制器。 2. **设置ServerSocketChannel**:配置 `ServerSocketChannel` 为非阻塞...

    nio演示代码

    在NIO模型中,以下几个核心组件是关键: 1. **通道(Channels)**:通道是数据传输的途径,可以将数据从一个地方传输到另一个地方。例如,FileChannel用于文件操作,SocketChannel用于网络通信。 2. **缓冲区...

    NIO的工作方式

    NIO的优势在于它可以有效地处理大量的并发连接,通过选择器监控多个通道,只需要少数几个线程就能管理成千上万的连接,减少了线程上下文切换的开销,提高了系统的整体性能。此外,NIO还支持零拷贝(Zero-Copy)技术...

    基于Groovy的NIO框架,仅供学习Java NIO使用。.zip

    在Groovy中实现NIO框架,首先需要理解以下几个核心概念: 1. **通道(Channels)**:通道是数据输入和输出的途径,它可以连接到硬件设备、文件、网络套接字等。Java NIO提供了多种通道类型,如FileChannel、...

    java NIO详细教程

    - **通道(Channel)**:Java NIO 中的通道主要有以下几种实现形式: - **FileChannel**:用于文件的读写操作。 - **DatagramChannel**:用于 UDP 数据报的发送和接收。 - **SocketChannel** 和 **...

    NIOServer

    代码可能包括以下几个关键部分: 1. **服务器端套接字(ServerSocketChannel)**:服务器首先会创建一个ServerSocketChannel,并将其绑定到特定的IP地址和端口号上,等待客户端的连接请求。 2. **选择器(Selector...

    基于Spring Boot + NIO实现的电商平台见证宝服务

    在本项目中,Spring Boot主要负责以下几个方面: 1. **依赖管理**:Spring Boot自动配置了大量常用的依赖,如数据访问、Web服务等,开发者只需声明依赖,即可自动引入相应的配置。 2. **启动类**:使用@SpringBoot...

    详细介绍 NIO与Netty编程-实战讲义详细pdf.7z

    **NIO(非阻塞I/O)与Netty编程**是现代Java网络应用开发中的重要技术,它们在处理高并发、低延迟的网络通信场景中起着关键作用。本讲义详细介绍了这两种技术,旨在帮助开发者更好地理解和运用它们。 ### 一、BIO...

Global site tag (gtag.js) - Google Analytics