java nio的严重BUG(续)

简介:
   上篇文章我谈到了 java nio的一个严重BUG,并且介绍了jetty是如何规避这个BUG的。我在将这部分代码整合进yanf4j的过程中发现了不少误判的情况,让我们看看误判是怎么发生的。jetty的解决方案是通过在select返回为0的情况下,计量Selector.select(timeout)执行的时间是否与传入的timeout参数相差太大(小于timeout的一半),如果相差太大,那么认为发生一次bug,如果发生的次数超过设定值,依据严重程度进行处理:第一尝试取消任何有效并且interestOps等于0的SelectionKey;第二次就是重新创建一个Selector,并将有效的Channel注册到新的Selector。误判的发生就产生于这个时间的计量上,看javadoc可以发现它是这样描述这个方法的:

    This method performs a blocking selection operation. It returns only after at least one channel is selected, this selector's wakeup method is invoked, or the current thread is interrupted, whichever comes first

    意思就是说这个方法将阻塞select调用,直到下列三种情况之一发生才返回:至少一个channel被选中;同一个Selector的wakeup方法被调用;或者调用所处的当前线程被中断。这三种情况无论谁先发生,都将导致select(timeout)返回。因此为了减少误判,你需要将这三种情况加入判断条件。Jetty的方案已经将select返回为0的情况考虑了,但是却没有考虑线程被中断或者Selector被wakeup的情况,在jetty的运行时也许不会有这两种情况的发生,不过我在windows上用jdk 6u7跑jetty的时候就发现了误判的日志产生。除了wakeup和线程中断这两种情形外,为了进一步提高判断效率,应该将操作系统版本和jdk版本考虑进来,如果是非linux系统直接不进行后续的判断,如果是jdk6u4以后版本也直接忽略判断,因此yanf4j里的实现大致如下:
            boolean  seeing  =   false ;
            
/**
             * 非linux系统或者超过java6u4版本,直接返回
             
*/
            
if  ( ! SystemUtils.isLinuxPlatform()
                    
||  SystemUtils.isAfterJava6u4Version()) {
                
return  seeing;
            }
            
/**
             * 判断是否发生BUG的要素:
             * (1)select返回为0
             * (2)wait时间大于0
             * (3)select耗时小于一定值
             * (4)非wakeup唤醒
             *  (5)非线程中断引起
             
*/
            
if  (JVMBUG_THRESHHOLD  >   0   &&  selected  ==   0
                    
&&  wait  >  JVMBUG_THRESHHOLD  &&  now  -  before  <  wait  /   4
                    
&&   ! this .wakenUp.get()  /*  waken up  */
                    
&&   ! Thread.currentThread().isInterrupted() /*  Interrupted  */ ) {
                
this .jvmBug.incrementAndGet();

    其中判断是否是线程中断引起的是通过Thread.currentThread().isInterrupted(),判断是否是wakeup是通过一个原子变量wakenUp,当调调用Selector.wakeup时候,这个原子变量更新为true。判断操作系统和jdk版本是通过System.getProperty得到系统属性做字符串处理即可。类似的代码示例:
public   static   final  String OS_NAME  =  System.getProperty( " os.name " );

    
private   static   boolean  isLinuxPlatform  =   false ;

    
static  {
        
if  (OS_NAME  !=   null   &&  OS_NAME.toLowerCase().indexOf( " linux " >=   0 ) {
            isLinuxPlatform 
=   true ;
        }
    }
    
public   static   final  String JAVA_VERSION  =  System
            .getProperty(
" java.version " );
    
private   static   boolean  isAfterJava6u4Version  =   false ;
    
static  {
        
if  (JAVA_VERSION  !=   null ) {
            
//  java4 or java5
             if  (JAVA_VERSION.indexOf( " 1.4. " >=   0
                    
||  JAVA_VERSION.indexOf( " 1.5. " >=   0 )
                isAfterJava6u4Version 
=   false ;
            
//  if it is java6,check sub version
             else   if  (JAVA_VERSION.indexOf( " 1.6. " >=   0 ) {
                
int  index  =  JAVA_VERSION.indexOf( " _ " );
                
if  (index  >   0 ) {
                    String subVersionStr 
=  JAVA_VERSION.substring(index  +   1 );
                    
if  (subVersionStr  !=   null   &&  subVersionStr.length()  >   0 ) {
                        
try  {
                            
int  subVersion  =  Integer.parseInt(subVersionStr);
                            
if  (subVersion  >=   4 )
                                isAfterJava6u4Version 
=   true ;
                        } 
catch  (NumberFormatException e) {

                        }
                    }
                }
                
//  after java6
            }  else
                isAfterJava6u4Version 
=   true ;
        }
    }
文章转自庄周梦蝶  ,原文发布时间2009-10-06
目录
相关文章
|
14天前
|
分布式计算 DataWorks Java
DataWorks操作报错合集之在使用MaxCompute的Java SDK创建函数时,出现找不到文件资源的情况,是BUG吗
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
26 0
|
2月前
|
存储 Java 数据处理
|
2月前
|
Java API
java中IO与NIO有什么不同
java中IO与NIO有什么不同
|
20天前
|
缓存 Java API
Java NIO和IO之间的区别
NIO(New IO),这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
17 1
|
25天前
|
监控 Java 开发者
深入理解 Java 网络编程和 NIO
【4月更文挑战第19天】Java网络编程基于Socket,但NIO(非阻塞I/O)提升了效率和性能。NIO特点是非阻塞模式、选择器机制和缓冲区,适合高并发场景。使用NIO涉及通道、选择器和事件处理,优点是高并发、资源利用率和可扩展性,但复杂度、错误处理和性能调优是挑战。开发者应根据需求选择是否使用NIO,并深入理解其原理。
|
27天前
|
存储 监控 Java
浅谈Java NIO
浅谈Java NIO
7 0
|
28天前
|
消息中间件 存储 Java
【Java NIO】那NIO为什么速度快?
是这样的,在NIO零拷贝出现之前,一个I/O操作会将同一份数据进行多次拷贝。可以看下图,一次I/O操作对数据进行了四次复制,同时来伴随两次内核态和用户态的上下文切换,众所周知上下文切换是很耗费性能的操作。
29 1
【Java NIO】那NIO为什么速度快?
|
1月前
|
存储 监控 Java
Java输入输出:什么是NIO(New I/O)?
Java NIO是一种高效I/O库,特征包括非阻塞性操作、通道(如文件、网络连接)、缓冲区和选择器。选择器监控通道状态变化,通知应用程序数据可读写,避免轮询,提升性能。示例代码展示了一个使用NIO的服务器,监听连接、读取数据并处理客户端通信。
14 1
|
3月前
|
移动开发 编解码 网络协议
用Java的BIO和NIO、Netty来实现HTTP服务器(三) 用Netty实现
用Java的BIO和NIO、Netty来实现HTTP服务器(三) 用Netty实现
|
3月前
|
网络协议 Java Linux
用Java来实现BIO和NIO模型的HTTP服务器(二) NIO的实现
用Java来实现BIO和NIO模型的HTTP服务器(二) NIO的实现