“NIO”的版本间的差异
Jihongchang(讨论 | 贡献) |
Jihongchang(讨论 | 贡献) |
||
第21行: | 第21行: | ||
− | === Channel(通道) === | + | ==== Channel(通道) ==== |
为了更容易地理解什么是 Channel,这里以 InputStream 为例来介绍什么是 Channel。 | 为了更容易地理解什么是 Channel,这里以 InputStream 为例来介绍什么是 Channel。 | ||
第43行: | 第43行: | ||
} | } | ||
− | </syntaxhighlight> | + | </syntaxhighlight>InputStream 其实就是一个用来读取文件的通道。只不过 InputStream 是一个单向的通道,只能用来读取数据。 |
+ | |||
+ | 而 NIO 中的 Channel 是一个双向的通道,不仅能读取数据,而且还能写入数据。 | ||
+ | |||
+ | |||
+ | |||
+ | ==== Buffer(缓冲区) ==== | ||
+ | 在上面的示例代码中,InputStream 把读取到的数据放在了 byte 数组中,如果用 OutputStream 写数据,那么也可以把 byte 数组中的数据写到文件中。 | ||
+ | |||
+ | 而在 NIO 中,数据只能被写到 Buffer 中,同理,读取的数据也只能放在 Buffer 中,由此可见 Buffer 是 Channel 用来读写数据的非常重要的一个工具。 | ||
+ | |||
+ | |||
+ | |||
+ | ==== Selector(选择器) ==== | ||
+ | Selector 是 NIO 中最重要的部分,是实现一个线程管理多个连接的关键,它的作用就是轮询所有被注册的 Channel,一旦发现 Channel 上被注册的事件发生,就可以对这个事件进行处理。 | ||
+ | |||
+ | |||
+ | === Buffer === | ||
+ | 在 Java NIO 中,Buffer 主要的作用就是与 Channel 进行交互。 | ||
+ | |||
+ | 它本质上是一块可读写数据的内存,这块内存中有很多可以存储 byte、int、char 等的小单元。 | ||
+ | |||
+ | 这块内存被包装成 NIO Buffer 对象,并提供了一组方法,来简化数据的读写。 | ||
+ | |||
+ | 在 Java NIO 中,核心的 Buffer 有7类,如图: |
2023年5月9日 (二) 00:56的版本
在 NIO(Nonblocking IO,非阻塞 IO)出现之前,Java 是通过传统的 Socket 来实现基本的网络通信功能的。
以服务端为例,其实现基本流程如图所示。
如果客户端还没有对服务端发起连接请求,那么 accept 就会阻塞[阻塞指的是暂停一个线程的执行以等待某个条件发生(例如某资源就绪)]。
如果连接成功,当数据还没有准备好的时候,对 read 的调用同样会阻塞。
当要处理多个连接的时候,就需要采用多线程的方式,由于每个线程都拥有自己的栈空间,而且由于阻塞会导致大量线程进行上下文切换,使得程序的运行效率非常低下。
因此在 J2SE 1.4 中引入了 NIO 来解决这个问题。
NIO 通过 Selector、Channels 和 Buffers 来实现非阻塞的 IO 操作。
NIO 是指 New I/O,既然有 New I/O,那么就会有 Old I/O,Old I/O 是指基于流的 I/O 方法。
NIO 是在 Java 1.4 中被纳入 JDK 中的,它最主要的特点是,提供了基于 Selector 的异步网络 I/O,使得一个线程可以管理多个连接。
基于 NIO 处理多个连接的结构图:
在介绍 NIO 的原理之前,首先介绍几个重要的概念:Channel(通道)、Buffer(缓冲区)和 Selector(选择器)。
Channel(通道)
为了更容易地理解什么是 Channel,这里以 InputStream 为例来介绍什么是 Channel。
传统的 IO 中经常使用下面的代码来读取文件:
import java.io.*;
public class NIOTest {
public static void main(String[] args) throws IOException {
File file = new File("input.txt");
InputStream is = new FileInputStream(file);
byte[] b = new byte[1024];
int read = 0;
while ((read = is.read(b)) != -1) {
//处理读取到的数据
}
is.close();
}
}
InputStream 其实就是一个用来读取文件的通道。只不过 InputStream 是一个单向的通道,只能用来读取数据。
而 NIO 中的 Channel 是一个双向的通道,不仅能读取数据,而且还能写入数据。
Buffer(缓冲区)
在上面的示例代码中,InputStream 把读取到的数据放在了 byte 数组中,如果用 OutputStream 写数据,那么也可以把 byte 数组中的数据写到文件中。
而在 NIO 中,数据只能被写到 Buffer 中,同理,读取的数据也只能放在 Buffer 中,由此可见 Buffer 是 Channel 用来读写数据的非常重要的一个工具。
Selector(选择器)
Selector 是 NIO 中最重要的部分,是实现一个线程管理多个连接的关键,它的作用就是轮询所有被注册的 Channel,一旦发现 Channel 上被注册的事件发生,就可以对这个事件进行处理。
Buffer
在 Java NIO 中,Buffer 主要的作用就是与 Channel 进行交互。
它本质上是一块可读写数据的内存,这块内存中有很多可以存储 byte、int、char 等的小单元。
这块内存被包装成 NIO Buffer 对象,并提供了一组方法,来简化数据的读写。
在 Java NIO 中,核心的 Buffer 有7类,如图: