Java NIO 类库Selector机制解析(续)

原创 2008年05月04日 10:55:00

Java NIO 类库Selector机制解析(续)

 

陈皓

http://blog.csdn.net/haoel

 

 

在前些天的《Java NIO类库Selector机制解析》文章中,我们知道了下面的事情:

 

1)SunJVM在实现Selector上,在LinuxWindows平台下的细节。

2)Selector类的wakeup()方法如何唤醒阻塞在select()系统调用上的细节。

 

先给大家做一个简单的回顾,在Windows下,SunJava虚拟机在Selector.open()时会自己和自己建立loopbackTCP链接;在Linux下,Selector会创建pipe。这主要是为了Selector.wakeup()可以方便唤醒阻塞在select()系统调用上的线程(通过向自己所建立的TCP链接和管道上随便写点什么就可以唤醒阻塞线程)

 

我们知道,无论是建立TCP链接还是建立管道都会消耗系统资源,而在Windows上,某些Windows上的防火墙设置还可能会导致JavaSelector因为建立不起loopbackTCP链接而出现异常。

 

而在我的另一篇文章《GDB调试Java程序》中介绍了另一个Java的解释器——GNUgij,以及编译器gcj,不但可以比较高效地运行Java程序,而且还可以把Java程序直接编译成可执行文件。

 

GNU的之所以要重做一个Java的编译和解释器,其一个重要原因就是想解释SunJVM的效率和资源耗费问题。当然,GNUJava编译/解释器并不需要考虑太多复杂的平台,他们只需要专注于Linux和衍生自Unix System V的操作系统,对于开发人员来说,离开了Windows,一切都会变得简单起来。在这里,让我们看看GNUgij是如何解释Selector.open()Selector.wakeup()的。

 

同样,我们需要一个测试程序。在这里,为了清晰,我不会例出所有的代码,我只给出我所使用的这个程序的一些关键代码。

 

我的这个测试程序中,和所有的Socket程序一样,下面是一个比较标准的框架,当然,这个框架应该是在一个线程中,也就是一个需要继承Runnable接口,并实现run()方法的一个类。(注意:其中的s是一个成员变量,是Selector类型,以便主线程序使用)

 

 

        //生成一个侦听端

        ServerSocketChannel ssc = ServerSocketChannel.open();

        //将侦听端设为异步方式

        ssc.configureBlocking(false);

        //生成一个信号监视器

        s = Selector.open();

        //侦听端绑定到一个端口

        ssc.socket().bind(new InetSocketAddress(port));

        //设置侦听端所选的异步信号OP_ACCEPT

        ssc.register(s,SelectionKey.OP_ACCEPT);

  

        System.out.println("echo server has been set up ......");

 

        while(true){

            int n = s.select();

            if (n == 0) { //没有指定的I/O事件发生

               continue;

            }    

            Iterator it = s.selectedKeys().iterator();    

            while (it.hasNext()) {

                SelectionKey key = (SelectionKey) it.next();

                if (key.isAcceptable()) { //侦听端信号触发

                     …… …… ……

                     …… …… ……

                }  

                if (key.isReadable()) { //socket可读信号

                     …… …… ……

                     …… …… ……                   

                }    

                it.remove();

            }

         }



 

而在主线程中,我们可以通过Selector.wakeup()来唤醒这个阻塞在select()上的线程,下面是写在主线程中的唤醒程序:

 

 

new Thread(this).start();

try{

    //Sleep 30 seconds

    Thread.sleep(30000);

    System.out.println("wakeup the select");

    s.wakeup();

}catch(Exception e){

        e.printStackTrace();

}

 

 

这个程序在主线程中,先启动一个线程,也就是上面那个Socket线程,然后休息30秒,为的是让上面的那个线程有阻塞在select(),然后打印出一条信息,这是为了我们用strace命令查看具体的系统调用时能够快速定位。之后调用的是Selectorwakeup()方法来唤醒侦听线程。

 

接下来,我们可以通过两种方式来编译这个程序:

1)使用gcj或是sunjavac编译成class文件,然后使用gij解释执行。

2)使用gcj直接编译成可执行文件。

(无论你用那种方法,都是一样的结果,本文使用第二种方法,关于gcj的编译方法,请参看我的《GDB调试Java程序》)

 

编译成可执行文件后,执行程序时,使用lsof命令,我们可以看到没有任何pipe的建立。可见GNU的解释更为的节省资源。而对于一个UnixC程序员来说,这意味着如果要唤醒select()只能使用pthread_kill()来发送一个信号了。下面就让我们使用strace命令来验证这个想法。

 

下图是使用strace命令来跟踪整个程序运行时的系统调用,我们利用我们的输出的“wakeup the select”字符串快速的找到了wakeup的实际系统调用。

 

 

果然,我们可可以看到,tgkill(5829, 5831, SIGHUP)这个系统调用,第一个参数是“源线程id”,第二个参数是“目的线程id”,第三个参数是“信号SIGHUP”。通过每一行前面的线程号我们可以看到紧接着tgkill后面的5831线程的“… select resumed”字样。

 

可见,GNU的确是使用最为传统的pthread_killkill系统调用向阻塞线程发信号的方法来实现Selector.wakeup()的,这也证明了GNUJava编译/解释器是不会消耗系统文件描述符的。而我们也终于看到了回归经典的Java实现机制。

 

欢迎使用MSN和邮件和我联系:haoel@hotmail.com

 

(转载时请注明作者和出处。未经许可,请勿用于商业用途)

更多文章请访问我的Blog: http://blog.csdn.net/haoel

 

java NIO selector全面深入理解

java NIO selector全面深入理解
  • lw305080
  • lw305080
  • 2016年04月21日 11:13
  • 2815

java nio的一个严重BUG

这个BUG会在linux上导致cpu 100%,使得nio server/client不可用,具体的详情可以看这里http://bugs.sun.com/bugdatabase/view_bug.do...
  • huoyunshen88
  • huoyunshen88
  • 2015年05月12日 17:22
  • 2594

NIO框架之MINA源码解析(二):mina核心引擎

MINA的底层还是利用了jdk提供了nio功能,mina只是对nio进行封装,包括MINA用的线程池都是jdk直接提供的。MINA的server端主要有accept、processor、session...
  • MINEZHANGHAO
  • MINEZHANGHAO
  • 2014年09月03日 08:42
  • 5235

Java_NIO类库Selector机制解析.doc

  • 2011年07月18日 22:54
  • 378KB
  • 下载

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

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

Java NIO类库Selector机制解析

本文转载自:http://blog.csdn.net/haoel/article/details/2224069 一、  前言   自从J2SE 1.4版本以来,JDK发布了全新的I/O类库...
  • xhh198781
  • xhh198781
  • 2011年07月06日 11:19
  • 2395

Java NIO类库Selector机制解析

from:http://haoel.blog.51cto.com/313033/124582 一、 前言 自从j2se 1.4版本以来,jdk发布了全新的i/o类库,简称nio,其不但引入了全新的...
  • javazhuanzai
  • javazhuanzai
  • 2012年01月10日 04:49
  • 401

Java NIO类库Selector机制解析

转载之:http://blog.csdn.net/haoel/article/details/2224055 Java NIO类库Selector机制解析(上)   赵锟  陈皓 ...
  • run_forever1
  • run_forever1
  • 2013年01月09日 15:11
  • 300

Java NIO——Selector机制源码分析系列——转

Java NIO——Selector机制源码分析---转 转自:http://www.cnblogs.com/davidwang456/p/3831617.html 一直不明白pipe是如何唤醒...
  • baidu_33116785
  • baidu_33116785
  • 2016年09月27日 17:24
  • 204

《Java源码解析》之NIO的Selector机制(Part3:Selector.select())

Selector.select()函数的分析:前面已经介绍过了Selector的open函数以及channel的register函数,现在分析最后一个函数:select()函数。selector.se...
  • u010853261
  • u010853261
  • 2016年12月07日 18:03
  • 1096
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java NIO 类库Selector机制解析(续)
举报原因:
原因补充:

(最多只允许输入30个字)