Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1531698
  • 博文数量: 3500
  • 博客积分: 6000
  • 博客等级: 准将
  • 技术积分: 43870
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-03 20:31
文章分类

全部博文(3500)

文章存档

2008年(3500)

我的朋友

分类:

2008-05-04 20:53:07

一起学习

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

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

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

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

六、 它山之石:ApacheMina框架了解Selector

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

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

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

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

4)要唤醒select方法,只需要调用Selectorwakeup()方法。

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

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

2) 阻塞时间到,即time out

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

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

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

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

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

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

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

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

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

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

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

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

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

八、 后记

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

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

· WindowsWindows XP SP2, Sun J2SE (build 1.7.0-ea-b23)

· LinuxUbuntu 7.10 Linux Kernel 2.6.22-14-generic, J2SE (build 1.6.0_03-b05)

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

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

下载本文示例代码


Java NIO类库Selector机制解析(下)Java NIO类库Selector机制解析(下)Java NIO类库Selector机制解析(下)Java NIO类库Selector机制解析(下)Java NIO类库Selector机制解析(下)Java NIO类库Selector机制解析(下)Java NIO类库Selector机制解析(下)Java NIO类库Selector机制解析(下)Java NIO类库Selector机制解析(下)Java NIO类库Selector机制解析(下)Java NIO类库Selector机制解析(下)Java NIO类库Selector机制解析(下)
阅读(320) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~