code-learning/netty/04-Netty 源码分析-NIO 基础(一)之简介.md

89 lines
4.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 精尽 Netty 源码分析 —— NIO 基础(一)之简介
# 1. 概述
Java NIO( New IO 或者 Non Blocking IO ) ,从 Java 1.4 版本开始引入的**非阻塞** IO ,用于替换**标准**( 有些文章也称为**传统**,或者 Blocking IO 。下文统称为 BIO ) Java IO API 的 IO API 。
> 老艿艿:在一些文章中,会将 Java NIO 描述成**异步** IO ,实际是不太正确的: Java NIO 是**同步** IO Java AIO ( 也称为 NIO 2 )是**异步** IO。具体原因推荐阅读文章
>
> - [《异步和非阻塞一样吗? (内容涉及 BIO, NIO, AIO, Netty)》](https://blog.csdn.net/matthew_zhang/article/details/71328697) 。
> - [《BIO与NIO、AIO的区别(这个容易理解)》](https://blog.csdn.net/skiof007/article/details/52873421)
>
> 总结来说,在 **Unix IO 模型**的语境下:
>
> - 同步和异步的区别:数据拷贝阶段是否需要完全由操作系统处理。
> - 阻塞和非阻塞操作:是针对发起 IO 请求操作后,是否有立刻返回一个标志信息而不让请求线程等待。
>
> 因此Java NIO 是**同步**且非阻塞的 IO 。
# 2. 核心组件
Java NIO 由如下**三个**核心组件组成:
- Channel
- Buffer
- Selector
后续的每篇文章,我们会分享对应的一个组件。
# 3. NIO 和 BIO 的对比
NIO 和 BIO 的区别主要体现在三个方面:
| NIO | BIO |
| :------------------- | :--------------- |
| 基于缓冲区( Buffer ) | 基于流( Stream ) |
| **非**阻塞 IO | 阻塞 IO |
| 选择器( Selector ) | 无 |
- 其中,选择器( Selector )是 NIO 能实现**非**阻塞的基础。
## 3.1 基于 Buffer 与基于 Stream
BIO 是面向字节流或者字符流的,而在 NIO 中,它摒弃了传统的 IO 流,而是引入 Channel 和 Buffer 的概念:从 Channel 中读取数据到 Buffer 中,或者将数据从 Buffer 中写到 Channel 中。
① 那么什么是**基于 Stream**呢?
在一般的 Java IO 操作中,我们以**流式**的方式,**顺序**的从一个 Stream 中读取一个或者多个字节,直至读取所有字节。因为它没有缓存区,所以我们就不能随意改变读取指针的位置。
② 那么什么是**基于 Buffer** 呢?
基于 Buffer 就显得有点不同了。我们在从 Channel 中读取数据到 Buffer 中,这样 Buffer 中就有了数据后,我们就可以对这些数据进行操作了。并且不同于一般的 Java IO 操作那样是**顺序**操作NIO 中我们可以随意的读取任意位置的数据,这样大大增加了处理过程中的灵活性。
> 老艿艿:**写入**操作,也符合上述**读取**操作的情况。
## 3.2 阻塞与非阻塞 IO
Java IO 的各种流是**阻塞**的 IO 操作。这就意味着,当一个线程执行读或写 IO 操作时,该线程会被**阻塞**,直到有一些数据被读取,或者数据完全写入。
------
Java NIO 可以让我们**非阻塞**的使用 IO 操作。例如:
- 当一个线程执行从 Channel 执行读取 IO 操作时,当此时有数据,则读取数据并返回;当此时无数据,则直接返回**而不会阻塞当前线程**。
- 当一个线程执行向 Channel 执行写入 IO 操作时,**不需要阻塞等待它完全写入**,这个线程同时可以做别的事情。
也就是说,线程可以将非阻塞 IO 的空闲时间用于在其他 Channel 上执行 IO 操作。所以,一个单独的线程,可以管理多个 Channel 的读取和写入 IO 操作。
## 3.3 Selector
Java NIO 引入 Selector ( 选择器 )的概念,它是 Java NIO 得以实现非阻塞 IO 操作的**最最最关键**。
我们可以注册**多个** Channel 到**一个** Selector 中。而 Selector 内部的机制,就可以自动的为我们不断的执行查询( select )操作,判断这些注册的 Channel 是否有**已就绪的 IO 事件( 例如可读,可写,网络连接已完成 )**。
通过这样的机制,**一个**线程通过使用**一个** Selector ,就可以非常简单且高效的来管理**多个** Channel 了。
# 4. NIO 和 AIO 的对比
考虑到 Netty 4.1.X 版本实际并未基于 Java AIO 实现,所以我们就省略掉这块内容。那么,感兴趣的同学,可以自己 Google 下 Java NIO 和 Java AIO 的对比。
具体为什么 Netty 4.1.X 版本不支持 Java AIO 的原因,可参见 [《NettyNetty 为啥去掉支持 AIO ?》](https://juejin.im/entry/5a8ed33b6fb9a0634c26801c) 文章。
也因此Netty 4.1.X 一般情况下,使用的是**同步非阻塞的 NIO 模型**。当然,如果真的有必要,也可以使用**同步阻塞的 BIO 模型**。
# 666. 彩蛋
参考文章如下:
- [《高并发 Java8NIO 和 AIO》](http://www.importnew.com/21341.html)
- [《Java NIO 的前生今世 之一 简介》](https://segmentfault.com/a/1190000006824091)
- [《Java NIO 系列教程(十二) Java NIO 与 IO》](http://ifeve.com/java-nio-vs-io/)