在Client/Server模型中,Server每每须要同时处理大量来自Client的访问请求,所以Server端需采用支持高并发访问的架构。一种简单而又直接的解决方案是“one-thread-per-connection”。这是一种基于阻塞式I/O的多线程模型。在该模型中,Server为每一个Client链接建立一个处理线程,每一个处理线程阻塞式等待可能达到的数据,一旦数据到达,则当即处理请求、返回处理结果并再次进入等待状态。因为每一个Client链接有一个单独的处理线程为其服务,所以可保证良好的响应时间。但当系统负载增大(并发请求增多)时,Server端须要的线程数会增长,这将成为系统扩展的瓶颈所在。(Java IO与NIO的区别)java
Java NIO不但引入了全新的高效的I/O机制,同时引入了基于Reactor设计模式的多路复用异步模式。NIO包中主要包含如下几种抽象数据类型。
* Channel(通道):NIO把它支持的I/O对象抽象为Channel。它模拟了通讯链接,相似于原I/O中的流(Stream),用户能够经过它读取和写入数据。目前已知的实例类有SocketChannel、ServerSocketChannel、DatagramChannel、FileChannel等。
* Buffer(缓冲区):Buffer是一块连续的内存区域,通常做为Channel收发数据的载体出现。全部数据都经过Buffer对象来处理。
* Selector(选择器):Selector类提供了监控一个和多个通道当前状态的机制。只要Channel向Selector注册了某种特定的事件,Selector就会监听这些事件是否会发生,一旦发生某个事件,便会通知对应的Channel。使用选择器,借助单一线程,就可对数量庞大的活动I/O通道实施监控和维护。设计模式
Java NIO的服务端只需启动一个专门的线程来处理全部的IO事件,这种通讯模型是怎么实现的呢?Java NIO采用了双向通道(channel)进行数据传输,而不是单向的流(stream),在通道上能够注册咱们感兴趣的事件。一共有如下四种事件:服务器
事件名 对应值
服务端接收客户端链接事件 SelectionKey.OP_ACCEPT(16)
客户端链接服务端事件 SelectionKey.OP_CONNECT(8)
读事件 SelectionKey.OP_READ(1)
写事件 SelectionKey.OP_WRITE(4)多线程
服务端和客户端各自维护一个管理通道的对象,咱们称之为selector,该对象能检测一个或多个通道 (channel) 上的事件。咱们以服务端为例,若是服务端的selector上注册了读事件,某时刻客户端给服务端发送了一些数据,阻塞I/O这时会调用read()方法阻塞地读取数据,而NIO的服务端会在selector中添加一个读事件。服务端的处理线程会轮询地访问selector,若是访问selector时发现有感兴趣的事件到达,则处理这些事件,若是没有感兴趣的事件到达,则处理线程会一直阻塞直到感兴趣的事件到达为止。下面是Java NIO的通讯模型示意图:架构
从下图中能够看出,当有读或写等任何注册的事件发生时,能够从Selector中得到相应的SelectionKey,同时从 SelectionKey中能够找到发生的事件和该事件所发生的具体的SelectableChannel,以得到客户端发送过来的数据。 使用NIO中非阻塞I/O编写服务器处理程序,大致上能够分为下面三个步骤:
1. 向Selector对象注册感兴趣的事件
2. 从Selector中获取感兴趣的事件
3. 根据不一样的事件进行相应的处理并发