Java NIO 在并发型服务器设计中的应用
丁辉
北京邮电大学PCN&CAD 中心,北京(100876 )
E-mail :lvsehaier@
摘 要:本文分析了应用传统阻塞型网络I/O 在进行服务器程序设计时的不足,在此基础上
研究了非阻塞型网络 I/O 的特性以及工作原理,给出了应用NIO 工具包设计并发型服务器
程序的实现。
关键词:阻塞,非阻塞,NIO, Java
1. 引言
随着多处理机体系结构的演变、网络技术的发展和分布式应用的兴起,并发型多任务的
服务器程序设计技术已越来越显示其重要性,这要求服务器程序能够在几百个甚至更多的客
户端同时发出请求信息的情况下,仍能保持高性能的并发处理机制,迅速完成所有并发请求
的处理。传统的并发型服务器设计是利用阻塞型网络I/O 以多线程的模式来实现的,然而由
于系统常常在进行网络读写时处于阻塞状态,会大大影响系统的性能;自Java1. 4 开始引入
了NIO(新I/O) API,通过使用非阻塞型I/O ,实现流畅的网络读写操作,为开发高性能并发
型服务器程序提供了一个很好的解决方案。
2. 传统阻塞型网络I/O 的不足
Java 平台传统的I/O 系统都是基于Byte (字节)和Stream (数据流)的,相应的I/O 操
作都是阻塞型的,所以服务器程序也采用阻塞型 I/O 进行数据的读、写操作。本文以 TCP
长连接模式来讨论并发型服务器的相关设计,为了实现服务器程序的并发性要求,系统由一
个单独的主线程来监听用户发起的连接请求,一直处于阻塞状态;当有用户连接请求到来时,
程序都会启一个新的线程来统一处理用户数据的读、写操作,其操作模式如图1[1]所示。
图1 基于阻塞I/O 的多线程TCP 服务器操作模式
这种模式的优点是简单、实用、易管理;然而缺点也是显而易见的:由于是为每一个客
户端分配一个线程来处理输入、输出数据,其线程与客户机的比例近似为 1:1,随着线程
数量的不断增加,服务器启动了大量的并发线程,会大大加大系统对线程的管理开销,这将
成为吞吐量瓶颈的主要原因;其次由于底层的I/O 操作采用的同步模式,I/O 操作的阻塞管
- 1 -
理粒度是以服务于请求的线程为单位的,有可能大量的线程会闲置,处于盲等状态,造成 I/O
资源利用率不高,影响整个系统的性能。
对于并发型服务器,系统用在阻塞型I/O 等待和线程间切换的时间远远多于CPU 在内
存中处理数据的时间,因此传统的阻塞型 I/O 已经成为制约系统性能的瓶颈。Java1.4 版本
后推出的NIO 工具包,提供了非阻塞型 I/O 的异步输入输出机制,为提高系统的性能提供
了可实现的基础机制。
3. NIO 包及工作原理
针对传统I/O 工作模式的不足,NIO 工具包提出了基于Buffer (缓冲区)、Channel (通
[2]
道)、Selector (选择器)的新模式 ;Selector (选择器)、可选择的Channel (通道)和
SelectionKey (选择键)配合起来使用,可以实现并发的非阻塞型I/O 能力。
3.1 NIO 工具包的成员[3]
3.1.1 Buffer (缓冲器)
Buffer 类是一个抽象类,它有7 个子类分别对应于七种基本的数据类型:ByteBuffer、
CharBuffer、DoubleBuffer 、FloatBuffer 、IntBuffer、LongBuffer 和ShortBuffer。每一个Buffer
对象相当于一个数据容器,可以把它看作内存中的一个大的数组,用来存储和提取所有基本
类型(boolean 型除外) 的数据。Buffer 类的核心是一块内存区,可以直接对其执行与内存有关
的操作,利用操作系统特性和能力提高和