Java NIO类库Selector机制解析(下)
赵锟 陈皓
http://blog.csdn.net/haoel
五、 迷惑不解 : 为什么要自己消耗资源?
令人不解的是为什么我们的Java的New I/O要设计成这个样子?如果说老的I/O不能多路复用,如下图所示,要开N多的线程去挨个侦听每一个Channel (文件描述符) ,如果这样做很费资源,且效率不高的话。那为什么在新的I/O机制依然需要自己连接自己,而且,还是重复连接,消耗双倍的资源?
通过WEB搜索引擎没有找到为什么。只看到N多的人在报BUG,但SUN却没有任何解释。
下面一个图展示了,老的IO和新IO的在网络编程方面的差别。看起来NIO的确很好很强大。但似乎比起C/C++来说,Java的这种实现会有一些不必要的开销。
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 341.25pt; HEIGHT: 411.75pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:%5CDOCUME~1%5CHAO~1.CHE%5CLOCALS~1%5CTemp%5Cmsohtml1%5C03%5Cclip_image001.png"></imagedata></shape>
六、 它山之石 : 从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的返回。
<shape id="_x0000_i1026" style="WIDTH: 6in; HEIGHT: 287.25pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:%5CDOCUME~1%5CHAO~1.CHE%5CLOCALS~1%5CTemp%5Cmsohtml1%5C03%5Cclip_image003.png"><font face="Times New Roman" size="3"></font></imagedata></shape>
从上图可见,这和我们之前的猜想正好一样。可见,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++方面有着相当的功底,相信自此以后,会有很多文章会由我和他一同发布。
本篇文章由我成文。但其全部著作权和版权归赵锟和我共同所有。我们欢迎大家转载,但希望保持整篇文章的完整性,并请勿用于任何商业用途。谢谢。
如果有任何问题,欢迎使用MSN和邮件和我联系:haoel@hotmail.com。
<<<<点此查看本文上篇
(转载时请注明作者和出处。未经许可,请勿用于商业用途)
更多文章请访问我的Blog: http://blog.csdn.net/haoel
分享到:
相关推荐
Java_NIO类库Selector机制解析.docJava_NIO类库Selector机制解析.docJava_NIO类库Selector机制解析.docJava_NIO类库Selector机制解析.doc
"Java NIO Selector 机制解析" ...了解Java NIO类库和Selector机制可以帮助程序员更好地使用Java NIO类库,提高I/O操作的性能。但需要注意到Java虚拟机对操作系统调用的影响,避免出现异常和错误。
Java 类库是Java编程语言的核心组成部分,它包含了大量的预定义类和接口,为开发者提供了丰富的功能,使得构建复杂的软件系统变得更加便捷。Java2 类库参考手册是一部全面介绍这些类库的权威指南,对于深入理解和...
【标签】"Java"明确了这个项目是用Java语言编写的,Java作为一门广泛应用的编程语言,其丰富的类库和强大的跨平台能力使得开发网络服务器成为可能。 至于【压缩包子文件的文件名称列表】中的“tiny-web-server-...
这里,我们将深度解析这个主题,探讨在Java环境下构建游戏服务器的关键知识点。 首先,我们需要理解Java语言的优势。Java以其跨平台的特性、丰富的类库以及强大的性能,成为了后端开发的首选语言之一,尤其适合大型...
解决这些问题通常需要深入理解NIO的工作原理,包括缓冲区(Buffer)、通道(Channel)、选择器(Selector)等核心概念,并且需要对Servlet容器的内部机制有一定的了解。 在提供的文件列表中,"src"目录可能包含了源...
1. **NIO(Non-blocking I/O)**:Java的非阻塞I/O模型,提供了通道(Channel)和选择器(Selector)等概念,极大地提高了处理大量并发连接的能力。在`sun.nio`包下,你可以找到`sun.nio.ch`子包,它包含了Java NIO...
- Java NIO还包括缓冲区(Buffer)、通道(Channel)、选择器(Selector)等概念。 5. JVM类加载机制 - 类加载过程包括加载、验证、准备、解析、初始化等步骤。 - 类加载器分为启动类加载器(BootstrapClassLoader)、...
在`java.nio`包中,`FileChannel`、`SocketChannel`和`Selector`等类是核心部分,通过查看其源码,开发者可以学习到如何高效地进行多路复用I/O,以及如何利用非阻塞特性来优化网络通信。 最后,`misc`(杂项)一词...
Java是一种广泛使用的面向对象的编程语言,以其跨平台、高性能和丰富的类库而备受赞誉。在IT行业,尤其是软件开发领域,Java工程师是需求量极大的职位。为了在Java面试中脱颖而出,深入理解Java语言的核心概念和技术...
4. **I/O与NIO**:Java API 1.6不仅有传统的基于流的I/O,还引入了非阻塞I/O(New IO,即NIO)框架,提供了一种更高效的数据传输方式,包括`java.nio`包中的通道(Channel)、缓冲区(Buffer)和选择器(Selector)...
JDK(Java Development Kit)是Oracle公司提供的用于开发Java应用程序的重要软件包,它包含了Java编译器、Java虚拟机(JVM)、Java类库以及各种开发和调试工具,是Java开发的基础。 JDK 1.4版本是Java历史上的一个...
文件《JAVA核心知识点整理.pdf》作为Java程序员面试准备资料,提供了一个全面的Java知识点回顾,涵盖JVM运行机制、多线程编程、集合框架、IO/NIO、类加载机制等内容。这些知识点对于应聘者理解Java技术栈、提升编程...
2. **IO流**:Java 1.6对输入/输出流进行了优化,提供了NIO(New Input/Output)框架,它支持选择器(Selector)和通道(Channel)等特性,提高了IO操作的性能和并发性。 3. **网络编程**:Java API 1.6提供Socket...
相对于传统的IO模型,NIO提供了选择器(Selector)和通道(Channel)等机制,可以实现多路复用,提高网络通信的效率,尤其适合高并发场景。 通过这个Java网络教程,学习者将能够熟练地运用Java进行网络编程,包括...
3. **NIO(非阻塞I/O)**:Java NIO(New Input/Output)是Java 1.4引入的新特性,它提供了与传统IO不同的I/O操作方式,支持选择器(Selector)、通道(Channel)和缓冲区(Buffer)。NIO允许程序在数据准备好时进行...
5. **java.nio**:非阻塞I/O,提供了Channel、Buffer和Selector等,提高了I/O性能。 6. **java.awt**和**javax.swing**:这两个包用于创建图形用户界面,其中java.awt提供基本组件,javax.swing提供了更为高级和...
NIO提供了一种非阻塞I/O模型,通过选择器(Selector)监控多个通道(Channel),实现同时处理多个输入输出任务。通道是NIO的核心概念,如FileChannel、SocketChannel等,它们可以从或向缓冲区(Buffer)读写数据。...
Java 1.6 API 中文版是针对Java SE(标准版)6.0平台的一份完整的官方文档,它为开发者提供了详细的类库、接口和方法的说明,是学习和开发Java应用程序的重要参考资料。这份API文档涵盖了Java语言的核心库,包括基础...
`java.nio`包提供了选择器(Selector)、通道(Channel)和缓冲区(Buffer)等组件,可以实现高并发和低延迟的网络服务。AIO(Java NIO.2)引入了`AsynchronousServerSocketChannel`和`AsynchronousSocketChannel`,...