I/O
(输入/输出)指的是计算机与外界或者一个程序与计算机其余部分交互的接口,相当于人的耳朵和嘴巴。在java编程中,我们最初接触到的就是以流的形式完成I/O
,正如它的名字:流,所有的I/O操作都只能是单向的一个或者多个字节的移动,而且还是阻塞式的,这就造成了效率的低下和资源的浪费。
为了解决这个问题,在JDK1.4
中引入了新方案:Java NIO
,它既可以说是New IO
,也可以说是No-Blocking IO
。NIO
和上面提到的IO
有相同的作用和目的,只是它使用不同的方式。原来的 I/O 库(在 java.io.*
中) 与 NIO (java.nio.*
)最重要的区别是数据打包和传输的方式。标准的IO
是基于输出流(OutputStream)
和输入流(InputStream)
进行操作的,而NIO
是基于通道(Channel)
和缓冲区(Buffer)
进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
NIO
主要包含了以下三个核心组件:
- Buffer
- Channel
- Selector
其实,除以上三个核心组件外,在java.nio.*
下还有其他很多类和组件,但它们只不过是上面三个组件共同使用的工具类。
Channel & Buffer(通道和缓冲区)
Channel
和标准I/O
的流类似,相同点是它们里面装的都是需要传输的数据,不同点是:
- 流具有方向性,如
InputStream
只能用于输入,OutputStream
只能用于输出;而Channel
没有方向,既可以作为输入,也可以作为输出- 流中的数据是以一个或者几个字节为单位进行移动,而
Channel
中的数据是以块为单位进行移动,这样效率更高- 可以直接向流中写入或读取数据,而
Channel
不能,它需要和Buffer
配合使用
Channel
有如下的几个重要实现:
- FileChannel
- DatagramChannel
- SocketChannel
- ServerSocketChannel
顾名思义,这些通道涵盖了UDP
和TCP
网络以及文件的读写。
Buffer
本质上是一块可以写入数据,然后从中读取数据的内存,其内部包含一个特定基本数据类型的数组,类似于缓冲流中的数组,主要用来连接Channel
和数据介质,相当于数据读写的中转站。
它主要有以下几个关键的Buffer实现:
- ByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
这些Buffer
覆盖了你能通过NIO
发送的基本数据类型:byte
, char
,short
, int
,long
, float
, double
。
Selector (选择器)
Selector
能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel
,从而管理多个网络连接。
要使用Selector
,得向Selector
注册Channel
,然后调用它的select()
方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件。