五、  迷惑不解 : 为什么要自己消耗资源?

令人不解的是为什么我们的Java的New I/O要设计成这个样子?如果说老的I/O不能多路复用,如下图所示,要开N多的线程去挨个侦听每一个Channel (文件描述符) ,如果这样做很费资源,且效率不高的话。那为什么在新的I/O机制依然需要自己连接自己,而且,还是重复连接,消耗双倍的资源?

通过WEB搜索引擎没有找到为什么。只看到N多的人在报BUG,但SUN却没有任何解释。

下面一个图展示了,老的IO和新IO的在网络编程方面的差别。看起来NIO的确很好很强大。但似乎比起C/C++来说,Java的这种实现会有一些不必要的开销。

六、  它山之石 : 从Apache的Mina框架了解Selector

上面的调查没过多长时间,正好同学赵锟的一个同事也在开发网络程序,这位仁兄使用了Apache的Mina框架。当我们把Mina框架的源码研读了一下后。发现在Mina中有这么一个机制:

1)Mina框架会创建一个Work对象的线程。

2)Work对象的线程的run()方法会从一个队列中拿出一堆Channel,然后使用Selector.select()方法来侦听是否有数据可以读/写。

3)最关键的是,在select的时候,如果队列有新的Channel加入,那么,Selector.select()会被唤醒,然后重新select最新的Channel集合。

4)要唤醒select方法,只需要调用Selector的wakeup()方法。

对于熟悉于系统调用的C/C++程序员来说,一个阻塞在select上的线程有以下三种方式可以被唤醒:

1)  有数据可读/写,或出现异常。

2)  阻塞时间到,即time out。

3)  收到一个non-block的信号。可由kill或pthread_kill发出。

所以,Selector.wakeup()要唤醒阻塞的select,那么也只能通过这三种方法,其中:

1)第二种方法可以排除,因为select一旦阻塞,应无法修改其time out时间。

2)而第三种看来只能在Linux上实现,Windows上没有这种信号通知的机制。

所以,看来只有第一种方法了。再回想到为什么每个Selector.open(),在Windows会建立一对自己和自己的loopback的TCP连接;在Linux上会开一对pipe(pipe在Linux下一般都是成对打开),估计我们能够猜得出来——那就是如果想要唤醒select,只需要朝着自己的这个loopback连接发点数据过去,于是,就可以唤醒阻塞在select上的线程了。

七、  真相大白 : 可爱的Java你太不容易了

使用Linux下的strace命令,我们可以方便地证明这一点。参看下图。图中,请注意下面几点:

1)  26654是主线程,之前我输出notify the select字符串是为了做一个标记,而不至于迷失在大量的strace log中。

2)  26662是侦听线程,也就是select阻塞的线程。

3)  图中选中的两行。26654的write正是wakeup()方法的系统调用,而紧接着的就是26662的epoll_wait的返回。

从上图可见,这和我们之前的猜想正好一样。可见,JDK的Selector自己和自己建的那些TCP连接或是pipe,正是用来实现Selector的notify和wakeup的功能的。

这两个方法完全是来模仿Linux中的的kill和pthread_kill给阻塞在select上的线程发信号的。但因为发信号这个东西并不是一个跨平台的标准(pthread_kill这个系统调用也不是所有Unix/Linux都支持的),而pipe是所有的Unix/Linux所支持的,但Windows又不支持,所以,Windows用了TCP连接来实现这个事。

关于Windows,我一直在想,Windows的防火墙的设置是不是会让Java的类似的程序执行异常呢?呵呵。如果不知道Java的SDK有这样的机制,谁知道会有多少个程序为此引起的问题度过多少个不眠之夜,尤其是Java程序员。

八、  后记

文章到这里是可以结束了,但关于Java NIO的Selector引出来的其它话题还有许多,比如关于GNU的Java编译器又是如何,它是否会像Sun的Java解释器如此做傻事?我在这里先卖一个关子,关于GNU的Java编译器,我会在另外一篇文章中讲述,近期发布,敬请期待。

关于本文中所使用的实验平台如下:

  • ·        Windows:Windows XP + SP2, Sun J2SE (build 1.7.0-ea-b23)
  • ·        Linux:Ubuntu 7.10 + Linux Kernel 2.6.22-14-generic, J2SE (build 1.6.0_03-b05)

本文主要的调查工作由我的大学同学赵锟完成,我帮其验证调查成果及猜想。在此也向大家介绍我的大学同学赵锟,他也是一个技术高手,在软件开发方面,特别是Unix/Linux C/C++方面有着相当的功底,相信自此以后,会有很多文章会由我和他一同发布。

本篇文章由我成文。但其全部著作权和版权归赵锟和我共同所有。我们欢迎大家转载,但希望保持整篇文章的完整性,并请勿用于任何商业用途。谢谢。

转载自 http://blog.csdn.net/haoel/article/details/2224069

Java NIO类库Selector机制解析(下)的更多相关文章

  1. Java NIO类库Selector机制解析(上)

    一.  前言 自从J2SE 1.4版本以来,JDK发布了全新的I/O类库,简称NIO,其不但引入了全新的高效的I/O机制,同时,也引入了多路复用的异步模式.NIO的包中主要包含了这样几种抽象数据类型: ...

  2. Java NIO类库Selector机制解析--转

    一.  前言 自从J2SE 1.4版本以来,JDK发布了全新的I/O类库,简称NIO,其不但引入了全新的高效的I/O机制,同时,也引入了多路复用的异步模式.NIO的包中主要包含了这样几种抽象数据类型: ...

  3. Java NIO 选择器(Selector)的内部实现(poll epoll)

    http://blog.csdn.net/hsuxu/article/details/9876983 之前强调这么多关于linux内核的poll及epoll,无非是想让大家先有个认识: Java NI ...

  4. Java NIO 选择器(Selector)的内部实现(poll epoll)(转)

    转自:http://blog.csdn.net/hsuxu/article/details/9876983 之前强调这么多关于linux内核的poll及epoll,无非是想让大家先有个认识: Java ...

  5. Java NIO之Selector(选择器)

    历史回顾: Java NIO 概览 Java NIO 之 Buffer(缓冲区) Java NIO 之 Channel(通道) 其他高赞文章: 面试中关于Redis的问题看这篇就够了 一文轻松搞懂re ...

  6. JAVA代码设置selector不同状态下的背景

    Selector设置button点击效果(详细)以及常见问题https://www.jianshu.com/p/a0ddba6d7969 Android 代码动态设置TextView的背景.颜色Sel ...

  7. Java NIO之Selector

    选择器是JavaNIO重磅推出的一个概念:在旧有的系统中为了跟踪多端口消息,需要为每一个端口配备一个线程做监听:但是有了selector就不需要了,一个Selector可以管理一众渠道(channel ...

  8. Netty快速入门(05)Java NIO 介绍-Selector

    Java NIO Selector Selector是Java NIO中的一个组件,用于检查一个或多个NIO Channel的状态是否处于可读.可写.如此可以实现单线程管理多个channels,也就是 ...

  9. JAVA NIO 类库的异步通信框架netty和mina

    Netty 和 Mina 我究竟该选择哪个? 根据我的经验,无论选择哪个,都是个正确的选择.两者各有千秋,Netty 在内存管理方面更胜一筹,综合性能也更优.但是,API 变更的管理和兼容性做的不是太 ...

随机推荐

  1. hdu 4968 Improving the GPA (水 暴力枚举)

    题目链接 题意:给平均成绩和科目数,求可能的最大学分和最小学分. 分析: 枚举一下,可以达到复杂度可以达到10^4,我下面的代码是10^5,可以把最后一个循环撤掉. 刚开始以为枚举档次的话是5^10, ...

  2. UVA 11090 Going in Cycle!!(二分答案+判负环)

    在加权有向图中求平均权值最小的回路. 一上手没有思路,看到“回路”,第一想法就是找连通分量,可又是加权图,没什么好思路,那就转换题意:由求回路权值->判负环,求最小值->常用二分答案. 二 ...

  3. 【Java学习笔记】函数使用

    package aaa; public class aaa { public static int add(int a,int b) { return a+b; } public static voi ...

  4. Linux编译安装Darwin Streaming Server 6.0.3

    买回来VPS后就一直想在上面搭建一个流媒体服务,在网上搜索了很多资料,大部分都是介绍Linux中安装Darwin Streaming Server 5.5.5版本,因为这个版本提供了针对linux的安 ...

  5. 最简单的视音频播放示例6:OpenGL播放YUV420P(通过Texture,使用Shader)

    本文记录OpenGL播放视频的技术.上一篇文章中,介绍了一种简单的使用OpenGL显示视频的方式.但是那还不是OpenGL显示视频技术的精髓.和Direct3D一样,OpenGL更好的显示视频的方式也 ...

  6. http请求返回响应码的意思

    HTTP 状态响应码 意思详解/大全 HTTP状态码(HTTP Status Code)是用以表示网页服务器HTTP响应状态的3位数字代码.它由 RFC 2616 规范定义的,并得到RFC 2518. ...

  7. 最简单的基于FFMPEG的转码程序

    本文介绍一个简单的基于FFmpeg的转码器.它可以将一种视频格式(包括封转格式和编码格式)转换为另一种视频格式.转码器在视音频编解码处理的程序中,属于一个比较复杂的东西.因为它结合了视频的解码和编码. ...

  8. 五分钟solr4.5教程(搭建、运行)

    环境要求 jdk1.6及以上版本 solr发布版本 下载地址 http://lucene.apache.org/solr/mirrors-solr-latest-redir.html? 启动solr ...

  9. Java SE 6 新特性: Java DB 和 JDBC 4.0

    http://www.ibm.com/developerworks/cn/java/j-lo-jse65/index.html 长久以来,由于大量(甚至几乎所有)的 Java 应用都依赖于数据库,如何 ...

  10. Android欢迎界面的创建方法

    1.制作一张启动图片splash.png,放置在res->drawable-hdpi文件夹中.2.新建布局文件splash.xml <?xml version="1.0" ...