Java NIO(New IO)
前言
阻塞和非阻塞的区别? 到底阻塞在哪了? 同步和异步的区别在哪? 在开始正文前,先来看些前置知识
一般的 IO 要经历两个阶段
- 等待系统可读、可写(空等)
- 真正的读写(使用 cpu 读写,非常快)
下面看看常见的几种 IO 模型
- blocking IO :1和2阶段都阻塞
- nonblocking IO:只在2阶段阻塞,需要调用系统函数向内核不断轮询是否准备好数据
- IO multiplexing:和 nonblocking IO 一样, 只不过是分出一个线程去检查数据是否准备好,就是1阶段,其它线程负责第2阶段
- asynchronous IO:1和2阶段都交由内核完成,完成后通知用户进程
- 同步异步:调用方是否需要阻塞等待结果,如果需要阻塞就是同步,否则就是异步。
- 阻塞和非阻塞:除了异步其实都是阻塞,常见的阻塞非阻塞指的是1阶段,如 BIO 、NIO指的就是等待数据准备时是否挂起。
Java 中 NIO 和传统 IO 的区别:
io | nio |
---|---|
面向Stream | 面向Buffer |
阻塞 IO | 可以配置为非阻塞,多路复用 |
一、多路复用
非阻塞 IO 中需要用户线程在每个IO通路上,各自不断轮询IO状态,来判断是否有可处理的数据。如果把一个连接的可读可写事件剥离出来,使用单独的线程来对其进行管理。多个IO通路都复用这个管理器来管理socket状态,这个叫I/O多路复用。
Linux 对多路复用的支持
1. select
下面是 Linux man 手册上对 select 的描述。
NAME
select, pselect, FD_CLR, FD_ISSET,FD_SET,
FD_ZERO - synchronous I/O multiplexing
DESCRIPTION
select() allows a program to monitor multiple file descriptors,
waiting until one or more of the file descriptors become "ready" for
some class of I/O operation (e.g., input possible). A file
descriptor is considered ready if it is possible to perform a
corresponding I/O operation (e.g., read(2), or a sufficiently small
write(2)) without blocking.
select() can monitor only file descriptors numbers that are less than
FD_SETSIZE; poll(2) and epoll(7) do not have this limitation. See
BUGS.
select 对监听的数量有限制
2. poll
poll 与 select 没区别,采用了链表实现,没有数量限制。
3. epoll
select 和 poll 都是遍历文件描述符,epoll 是通过监听回调的机制处理。
二、Java NIO
Java NIO 由以下几个核心部分组成:
- Channels
- Buffers
- Selectors
下面看下简单的概念,原理暂不展开。
1. Channel
定义参见下方截取的 Java 注释。比传统的 IO 抽象层次更高。
/**
* A nexus for I/O operations.
*
* <p> A channel represents an open connection to an entity such as a hardware
* device, a file, a network socket, or a program component that is capable of
* performing one or more distinct I/O operations, for example reading or
* writing.
*/
2. Buffer
下面是 Java 类注释的部分描述。
/**
* A container for data of a specific primitive type.
*/
3. Selector
就是上文提到的“多路复用”。