Java NIO 类库Selector机制解析(续)
陈皓
http://blog.csdn.net/haoel
在前些天的《Java NIO类库Selector机制解析》文章中,我们知道了下面的事情:
1)Sun的JVM在实现Selector上,在Linux和Windows平台下的细节。
2)Selector类的wakeup()方法如何唤醒阻塞在select()系统调用上的细节。
先给大家做一个简单的回顾,在Windows下,Sun的Java虚拟机在Selector.open()时会自己和自己建立loopback的TCP链接;在Linux下,Selector会创建pipe。这主要是为了Selector.wakeup()可以方便唤醒阻塞在select()系统调用上的线程(通过向自己所建立的TCP链接和管道上随便写点什么就可以唤醒阻塞线程)
我们知道,无论是建立TCP链接还是建立管道都会消耗系统资源,而在Windows上,某些Windows上的防火墙设置还可能会导致Java的Selector因为建立不起loopback的TCP链接而出现异常。
而在我的另一篇文章《用GDB调试Java程序》中介绍了另一个Java的解释器——GNU的gij,以及编译器gcj,不但可以比较高效地运行Java程序,而且还可以把Java程序直接编译成可执行文件。
GNU的之所以要重做一个Java的编译和解释器,其一个重要原因就是想解释Sun的JVM的效率和资源耗费问题。当然,GNU的Java编译/解释器并不需要考虑太多复杂的平台,他们只需要专注于Linux和衍生自Unix System V的操作系统,对于开发人员来说,离开了Windows,一切都会变得简单起来。在这里,让我们看看GNU的gij是如何解释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命令查看具体的系统调用时能够快速定位。之后调用的是Selector的wakeup()方法来唤醒侦听线程。
接下来,我们可以通过两种方式来编译这个程序:
1)使用gcj或是sun的javac编译成class文件,然后使用gij解释执行。
2)使用gcj直接编译成可执行文件。
(无论你用那种方法,都是一样的结果,本文使用第二种方法,关于gcj的编译方法,请参看我的《用GDB调试Java程序》)
编译成可执行文件后,执行程序时,使用lsof命令,我们可以看到没有任何pipe的建立。可见GNU的解释更为的节省资源。而对于一个Unix的C程序员来说,这意味着如果要唤醒select()只能使用pthread_kill()来发送一个信号了。下面就让我们使用strace命令来验证这个想法。
下图是使用strace命令来跟踪整个程序运行时的系统调用,我们利用我们的输出的“wakeup the select”字符串快速的找到了wakeup的实际系统调用。
<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: 431.25pt; HEIGHT: 264pt" type="#_x0000_t75"><imagedata o:title="java" src="file:///C:%5CDOCUME~1%5CHAO~1.CHE%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.png"></imagedata></shape>
果然,我们可可以看到,tgkill(5829, 5831, SIGHUP)这个系统调用,第一个参数是“源线程id”,第二个参数是“目的线程id”,第三个参数是“信号SIGHUP”。通过每一行前面的线程号我们可以看到紧接着tgkill后面的5831线程的“… select resumed”字样。
可见,GNU的确是使用最为传统的pthread_kill或kill系统调用向阻塞线程发信号的方法来实现Selector.wakeup()的,这也证明了GNU的Java编译/解释器是不会消耗系统文件描述符的。而我们也终于看到了回归经典的Java实现机制。
欢迎使用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以其跨平台的特性、丰富的类库以及强大的性能,成为了后端开发的首选语言之一,尤其适合大型、复杂的游戏服务器开发。 1. **网络编程**:游戏服务器的核心是处理客户端的连接请求和数据传输。Java的Socket编程...
解决这些问题通常需要深入理解NIO的工作原理,包括缓冲区(Buffer)、通道(Channel)、选择器(Selector)等核心概念,并且需要对Servlet容器的内部机制有一定的了解。 在提供的文件列表中,"src"目录可能包含了源...
- Java NIO还包括缓冲区(Buffer)、通道(Channel)、选择器(Selector)等概念。 5. JVM类加载机制 - 类加载过程包括加载、验证、准备、解析、初始化等步骤。 - 类加载器分为启动类加载器(BootstrapClassLoader)、...
1. **NIO(Non-blocking I/O)**:Java的非阻塞I/O模型,提供了通道(Channel)和选择器(Selector)等概念,极大地提高了处理大量并发连接的能力。在`sun.nio`包下,你可以找到`sun.nio.ch`子包,它包含了Java NIO...
在`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)...
文件《JAVA核心知识点整理.pdf》作为Java程序员面试准备资料,提供了一个全面的Java知识点回顾,涵盖JVM运行机制、多线程编程、集合框架、IO/NIO、类加载机制等内容。这些知识点对于应聘者理解Java技术栈、提升编程...
JDK(Java Development Kit)是Oracle公司提供的用于开发Java应用程序的重要软件包,它包含了Java编译器、Java虚拟机(JVM)、Java类库以及各种开发和调试工具,是Java开发的基础。 JDK 1.4版本是Java历史上的一个...
2. **IO流**:Java 1.6对输入/输出流进行了优化,提供了NIO(New Input/Output)框架,它支持选择器(Selector)和通道(Channel)等特性,提高了IO操作的性能和并发性。 3. **网络编程**:Java API 1.6提供Socket...
3. **NIO(非阻塞I/O)**:Java NIO(New Input/Output)是Java 1.4引入的新特性,它提供了与传统IO不同的I/O操作方式,支持选择器(Selector)、通道(Channel)和缓冲区(Buffer)。NIO允许程序在数据准备好时进行...
相对于传统的IO模型,NIO提供了选择器(Selector)和通道(Channel)等机制,可以实现多路复用,提高网络通信的效率,尤其适合高并发场景。 通过这个Java网络教程,学习者将能够熟练地运用Java进行网络编程,包括...
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.nio`包提供了选择器(Selector)、通道(Channel)和缓冲区(Buffer)等组件,可以实现高并发和低延迟的网络服务。AIO(Java NIO.2)引入了`AsynchronousServerSocketChannel`和`AsynchronousSocketChannel`,...
Java 1.6 API 中文版是针对Java SE(标准版)6.0平台的一份完整的官方文档,它为开发者提供了详细的类库、接口和方法的说明,是学习和开发Java应用程序的重要参考资料。这份API文档涵盖了Java语言的核心库,包括基础...