BIO与NIO的区别?

123 阅读4分钟

为了更好地理解,建议联系前文 请解释:同步/异步?阻塞/非阻塞?I/O多路复用?Reactor模型?一起阅读。

1. 概念介绍

在JDK1.4之前,Java只有一种IO模型,即标准IO,它是阻塞式的IO。

直到JDK1.4开始,Java提供了一个新的包java.nio(这里的nio,我个人认为是New IO的意思,表示一种新的IO方式),它不仅支持阻塞式的IO,还可以实现非阻塞式的IO。

到这里,就开始区分BIO和NIO的概念了。

BIO指的是阻塞式IO,即Blocking IO;

NIO指的是非阻塞式的IO,这里就是Non-Blocking IO的缩写了。

JDK1.7中还新增了一个异步IO,即Asynchronous IO (AIO),可以实现异步的IO模型和Proactor线程模型。

2. 主要区别

(1) 阻塞与非阻塞

BIO是阻塞的,当需要输入/输出数据时,线程会被阻塞,直到读写任务完成。
在高并发的场景下,对于每一个读写请求都需要创建一个新的线程进行处理,十分耗费资源。

NIO是非阻塞的,它可以做到通过一个线程处理多个读写请求。
假设有10000个请求过来,根据实际情况,可以分配50或100个线程来处理,而不是像BIO一样需要10000个线程来处理。

(2) 面向流与面向块

BIO是面向流的,意味着每次从流中读取/向流中写入一个字节(字节流)或多个字节(字符流)。 image.png

NIO是面向块的,而块的效率比流高。它基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或是从缓冲区写入到通道内image.png

图片来自这里

(流和块的概念可以这么想象,对于流来说需要一直去接着它,如果一些流丢失就会造成数据丢失,因此线程就阻塞住不能去干别的事;而块就不一样,可以等到数据全部写入到缓冲区中形成一个数据块之后再去处理它,在此期间线程可以去处理其他的请求。)

(3) 选择器

在之前的文章中我们说过,非阻塞式IO实际上还可以细分为同步非阻塞式IO、多路复用IO、信号驱动IO、异步IO等等,这里指的是哪一种呢?

实际上,NIO提供的就是基于事件驱动的非阻塞IO的实现,即多路复用IO,采用的线程模型就是Reactor模型。

Reactor模式中有Reactor和Handler的概念,其中Reactor用于监控socket并且对读写任务进行分发,由Handler来执行任务处理。在NIO中,是由Selector(选择器)来监听多个通道的,因此,一个线程可以处理多个通道的读写请求。而BIO中没有选择器的概念。

image.png

3. 适用场景

BIO适用于连接数比较少且固定的架构,这种方式对服务器资源要求比较高,因为线程需要创建很多。BIO是JDK1.4以前的唯一选择,但程序直观简单易理解;

NIO适用于连接数较多且连接比较短(轻操作)的架构,比如聊天服务器,因为如果大多数连接都比较长的话,会增加轮询的开销。

AIO适用于连接数较多且连接比较长(重操作)的结构,比如图片服务器,可以充分利用操作系统的能力。

4. NIO与Netty

NIO虽然性能优于BIO,但是它有一个缺点就是编程复杂,想要实现一个NIO网络应用,其开发工作量和难度都比较大。

因此,Netty就应运而生了。

Netty是目前最流行的NIO框架,它提供异步的、基于事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

也就是说,Netty相当于简化了网络应用的编程开发过程,可以帮助你快速和简单地开发出一个NIO网络应用。 当前 当前Netty已经得到了广泛的应用,比如ElasticSearch、Dubbo内部就使用了Netty。