在前些天的《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的实际系统调用。
果然,我们可可以看到,tgkill(5829, 5831, SIGHUP)这个系统调用,第一个参数是“源线程id”,第二个参数是“目的线程id”,第三个参数是“信号SIGHUP”。通过每一行前面的线程号我们可以看到紧接着tgkill后面的5831线程的“… select resumed”字样。
可见,GNU的确是使用最为传统的pthread_kill或kill系统调用向阻塞线程发信号的方法来实现Selector.wakeup()的,这也证明了GNU的Java编译/解释器是不会消耗系统文件描述符的。而我们也终于看到了回归经典的Java实现机制。
相关推荐
本文将深入探讨Java NIO中的Selector机制,并通过源码分析来理解其实现原理。 Selector机制是Java NIO中的核心组件,它允许单线程同时监控多个通道(Channels)的状态变化,例如连接就绪、数据可读或可写等。这种...
- `java.nio` 包中的非阻塞I/O模型,如`Selector`、`Channel`、`Buffer`,提供了更高的并发性能。 8. **线程工具类**: - `java.util.concurrent` 包提供了丰富的并发工具,如`ExecutorService`、`Future`、`...
`java.nio`包下的`Selector`、`ServerSocketChannel`和`SocketChannel`等类是实现NIO的关键。 网络编程还涉及到URL(统一资源定位符)、URI(统一资源标识符)和URLConnection。URL是访问网络资源的完整地址,而URI...
### 基于时间的NIO多线程服务器——深入解析与关键技术点 #### 引言 在服务器端编程领域,随着互联网应用的不断发展,如何高效处理大量的并发连接成为了一个重要议题。Java NIO(非阻塞I/O)作为一种先进的I/O处理...
【Java学习笔记——全面解析】 Java作为一种广泛应用的高级编程语言,是软件开发领域的核心力量。这份"学习笔记——资料"涵盖了Java学习的各个方面,旨在帮助初学者和有经验的开发者巩固基础,提升技能。以下是对这...
在Java编程领域,JDK 7引入了一个重要的更新——NIO2.0,也被称为“New I/O 2.0”或“AIO”(Asynchronous I/O)。这个更新极大地提升了Java处理I/O操作的能力,特别是在文件系统交互和网络通信方面。NIO2.0主要增加...
NIO模型在Java中通过Selector和Channel实现,能更有效地处理大量并发连接,而BIO模型则更为简单,但对高并发场景支持较差。根据Tomcat的配置,它会选择合适的I/O模型来读取Socket上的字节流,并将其转化为HTTP请求...
《通天塔——深入解析Java NIO》 Java NIO(New Input/Output)是Java在JDK 1.4引入的一个新特性,它为Java提供了另一种与I/O相关的编程模型,相较于传统的IO,NIO具有更高的性能和更好的灵活性。在传统IO中,我们...
在NIO部分,文档详细讲解了缓冲区、通道(Channel)、非阻塞IO的实现、选择器(Selector)等概念和机制。 4. JVM类加载机制: JVM类加载机制负责将Java类装入JVM中执行。这部分内容涉及到类加载过程中的各个步骤...
Java技能百练——网络篇是针对Java开发者在网络编程方面的深入学习和实践。在这个主题中,我们将探讨Java在处理网络通信、数据传输以及网络服务开发等多个关键领域的应用。下面,我们将详细解析Java网络编程的一些...
- **解决 Java NIO 的限制**:针对 Java NIO 中存在的问题(如内存泄漏、Selector 的使用复杂度高等),Netty 提供了一系列优化方案,确保了框架的稳定性和可靠性。 #### 4. 总结 Netty 作为一款高性能的网络通信...
### Java+TCPIP+Socket编程(中文版) —— 关键知识点详解 #### 第1章 简介 - **计算机网络、分组报文和协议** 计算机网络是通过通信设备和线路将地理位置分散、功能独立的多个计算机系统互连起来,以功能完善的...
14. **NIO(New IO)与NIO.2**:理解通道(Channel)、缓冲区(Buffer)、选择器(Selector)的概念,以及非阻塞I/O的优势。 15. **Java 8新特性**:掌握Lambda表达式、Stream API、Optional类、日期时间API、函数...
《深入解析Core Java技术面试》 Core Java是Java编程的基础,涵盖了从基本语法到高级特性的广泛知识领域。对于任何想要在Java开发领域深化技能或准备面试的人来说,掌握Core Java技术至关重要。本资料集合旨在帮助...
### Netty源码解析——服务启动过程 #### 一、Netty概述 Netty是一个高性能、异步事件驱动的网络应用框架,它被广泛应用于快速开发高性能协议服务器和客户端。Netty通过高度优化的设计和实现提供了低延迟和高吞吐...
`java.nio`包包含了与NIO相关的类,如`FileChannel`、`SocketChannel`和`Selector`等。 在多线程处理上,Java 4引入了`java.util.concurrent`包,这是Java并发库的基础,包含了各种高级并发工具,如`...
- NIO(New IO):理解非阻塞IO模型,Channel、Buffer和Selector的作用。 7. **网络编程** - Socket编程:建立TCP/IP连接,发送和接收数据。 - HttpURLConnection:HTTP协议的Java实现,用于发送HTTP请求。 8. ...
### Java_TCPIP_Socket编程(中文版) #### 第1章 简介 - **计算机网络、分组报文和协议**:计算机网络是通过物理介质(如电缆或无线信号)连接起来的一组计算机,它们可以相互通信并共享资源。在网络中传输的数据...
1. **TCP和UDP协议**:Java支持两种主要的传输层协议——TCP(传输控制协议)和UDP(用户数据报协议)。TCP提供可靠的数据传输,保证顺序和无损,而UDP则以较小的开销提供快速但不可靠的服务。 2. **Socket编程**:...