目录
第一章NIO的概述
Java NIO (New IO 或Non Blocking IO) 是从java1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。 NIO支持面向缓存区的,基于通信的IO操作。NIO将以更加高效的方式进行文件的读写操作。
1.1 阻塞IO
通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有可供读取的数据。同样,写入调用将会阻塞直至数据能够写入。传统的Server/Client模式会基于TPR(Thread per Request),服务器会为每个客户端请求建立一个线程,由该线程单独负责处理一个客户请求。这种模式带来的一个问题就是线程数量剧增,大量的的线程会增大服务器的开销。大多数的实现为了避免这个问题,都采用线程池模型,并设置线程池线程的最大数量,这由带来了新的问题,如线程池中有100个线程,而有100个用户都在进行大文件下载,会导致第101个用户的请求无法及时处理,即便第101个用户只想请求一个几KB大小的页面。传统的Serve/Client模式如下图所示:
线程池模型
1.2 非阻塞IO(NIO)
NIO中非阻塞I/O采用了基于Reactor模式的工作方式,I/O调用不会被阻塞,相反是注册感兴趣的特定I/O事件,如可读数据到达,新的套接字连接等等,在发生特定事件时,系统在通知我们。NIO中实现非阻塞I/O的核心对象就时Selector,Selector就是注册各种I/O事件地方,而且但我们感兴趣的事件发生时,就是这个对象告诉我们所发生的事件,如下图所示:
从图中可以看出,当读或写等任何注册的事件发生时,可以从Selector中获得相应的SelectionKey,同时从SelectionKey中可以找到发生事件所发生的具体的Selectable Channel,以获得客户端发送过来的数据。
非阻塞指的是IO事件本身不阻塞,但获取IO事件的select()方法是需要阻塞等待的,区别是阻塞的IO会阻塞在IO操作上,NIO阻塞在事件获取上,没有事件就没有IO,从高层次看IO就不阻塞了,也就是说只有IO已经发生发生那么我们才评估IO是否阻塞,但是select()阻塞的时候IO还没发生,何谈IO的阻塞?NIO的本质是延迟IO操作到真正发生IO的时候,而不是以前的只要IO流打开就一直等待IO操作。
1.3 NIO 概述
java NIO 由以下几个核心部分组成
- Channels
- Buffers
- Selectors
虽然java NIO 中除此之外还有很多类和组件,但Channel,Buffer和Selector构成了核心的API。其他组件,如Pipe和FileLock,只不过是与三个核心组件共同使用的工具类。
1.3.1 Channel
首先说一下Channel,可以翻译成“通道”。Channel和I0 中的 Stream(流)是差不多一个等级的。只不过 Stream 是单向的,警如: InputStream,OutputStream.而Channel 是双向的,既可以用来进行读操作,又可以用来进行写操作。
NIO中的Channel的主要实现有: FileChannel、DatagramChannel.SocketChannel和ServerSocketChannel,这里看名字就可以猜出个所以然来:分别可以对应文件10、UDP和TCP (Server和 Client)
1.3.2 Buffer
NIO 中的关键 Buffer 实现有: ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer.IntBuffer, LongBuffer, ShortBuffer,分别对应基本数据类型: byte, char, double,float, int, long, short.
1.3.3 Selector
Selector运行单线程处理多个 Channel,如果你的应用打开了多个通道,但每个连接的流量都很低,使用 Selector 就会很方便。例如在一个聊天服务器中。要使用Selector,得向 Selector注册 Channel,然后调用它的 select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件事件的例子有如新的连接进来、数据接收等。