Java BIO, NIO, AIO的一些粗浅认识

1. 阻塞与非阻塞

"阻塞"与“非阻塞”概念经常和“同步”、“异步”混淆。在Java程序中,很多线程通常处于阻塞(blocking)状态,而同步(并不是指多线程同步的Synchronized)并不是这样,同步通常是指步骤需要一步步来完成,就想常规的代码一条条地执行一样,但异步可以在没有执行完当前这行代码之前,就执行下一行代码,就像很多JS代码、UI控件、后台启动线程等。

相对于阻塞来讲,同步的程序线程应当是处于Running状态的。线程处于Blocking状态就差不多可以看成是睡眠的,也就是说它什么也没法做,只有一直等待一个信号的产生才能唤醒。处于Running状态下的线程是活跃的,在这种情况下可以去做很多其他的事情,可以一直去检测一些事情是否做好。


2. BIO (Blocking I/O)

Blocking I/O(阻塞I/O),这是最古老的Java通信机制,在这种模型中,应用程序首先会通过System Call发送请求给内核(Kernel),然后由内核去进行网络通信,应用程序如果发起的系统调用是读操作,在内核准备好数据以前,这个线程将会被挂起,一直等待下去,直到有返回的数据在内核中准备好位置,或者在设置SoTimeout后超时被唤醒。

假如抛开超时机制在网络等待机制中的作用,发起read()操作等待远程返回数据的过程由以下两个阶段组成。

阶段1:等待I/O返回数据,这取决于I/O请求的目标返回数据的速度。例如在网络I/O请求中,在远程返回数据前也需要经过一些处理才返回数据,远程输出数据后将取决于网络本身的速度及数据本身大小。

阶段2:返回数据首先被填充到内核(Kernel)的缓冲区里,然后再从内核区将数据向进程内部拷贝(copy data from kernel to user)。这个过程完成后,应用程序才会继续向下执行。

根据上面的过程,在BIO过程中,程序与内核交互的过程如下图所示:



2. NIO (New I/O)

Java从1.4版本开始支持NIO(New IO),可以实现非阻塞I/O的。非阻塞I/O和阻塞I/O有个很明显的区别是:当发生第一次System Call请求后,线程并没有被阻塞,但它没有做别的事情,而是在不断发起System Call请求。

这样操作似乎在空耗CPU,给人感觉还不如一直挂起等待返回,那样至少会让出CPU资源。其实,每次System Call只是看看数据准备好没有,通常它的时间是很短暂的,这样的动作完全只用一个线程来完成对很多事件的监听。换句话说,其它的线程可以去干别的事,只需要某个线程定期来做下检测即可,在设计上注意这个检测频率,就可以达到效率高且节约资源的目的。



总结:

IONIO
Stream OrientedBuffer oriented
Blocking IONon Blocking IO
 Selectors



3. AIO (Asynchronous I/O)

JDK 1.7引入了NIO 2.0,也就是AIO,又叫异步IO。下面用“物流送货”来比如Java中的IO模型:

① BIO:你需要到物流的中转站去等货且不能离开中转站,如果货没到,其他的事情就别想做。

② NIO:每天去检测一下货物是否到了,这个动作十分简单,可以让每个小区派1个人去看看有没有这个小区的货物,如果有就带回来,或者这个人通知你去物流中转站拿货。

③ AIO:货到的时候送货上门,换句话说,去拿货的路途虽然不长,但是由别人帮你承担了。



使用AIO读取文件并不代表读取更快,我们不能用AIO读取一个大文件与用BIO来对比速度,这样没有任何意义。因为AIO的目的在于I/O过程中程序去做别的事情,也就是在并发时,更少的资源可以做更多的事情,并不是看在I/O过程中谁更快,它也做不到这点,因为能做到I/O更快只有提高磁盘或者网络本身的速度,而这些I/O模型只是调度I/O的机制而已。

AIO相对NIO,在某种意义上讲更加提高了资源利用率,但这仅仅是相对进程本身而言,对于整个服务器来说,还得看实际情况,因为进程不想做的事情交给内核去做了。AIO应当更加适合运用在I/O密集型系统中,BIO也并非没有价值,它使得交互简化,而且在很多情况下本身没有必要使用异步和非阻塞。


### JavaBIONIOAIO 的区别 #### 同步阻塞 I/O (BIO) 同步阻塞 I/O 是最传统的 I/O 模型。在这种模式下,当应用程序发起一个 I/O 请求时,调用线程会被挂起直到请求完成。这意味着如果当前线程正在处理某个耗时的 I/O 操作,则该线程无法继续执行其他任务。 对于服务器端开发而言,通常需要为每一个客户端连接创建一个新的线程来处理通信过程中的读写操作。这种方式虽然简单直观,但在高并发场景下的资源消耗非常大,因为每个活跃连接都需要占用独立的工作线程[^5]。 ```java ServerSocket server = new ServerSocket(port); while(true){ Socket client = server.accept(); // 此处会发生阻塞 } ``` #### 非阻塞 I/O (NIO) 非阻塞 I/O 则允许程序在发出 I/O 调用时不被阻塞,而是立即返回给调用方。具体来说,在 NIO 下可以通过 `Selector` 对象管理多个 Channel 实例的状态变化事件(如可读、可写)。一旦有就绪状态发生改变,就会触发相应的回调逻辑去处理实际的数据交换工作。这种机制大大提高了单个线程所能承载的最大并发量,并且降低了上下文切换带来的开销[^3]。 ```java // 创建 Selector 并注册感兴趣的事件类型 Selector selector = Selector.open(); serverChannel.configureBlocking(false); serverChannel.register(selector, SelectionKey.OP_ACCEPT); // 处理已准备好的 channel int readyChannels = selector.select(); if (readyChannels == 0) continue; Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while(keyIterator.hasNext()){ SelectionKey key = keyIterator.next(); if(key.isAcceptable()) { // handle accept event... } else if (key.isReadable()) { // handle read event... } ... } ``` #### 异步非阻塞 I/O (AIO/NIO.2) 自JDK 7引入以来,AIO 提供了一个更加高级别的抽象层用于构建高效的网络服务端应用。不同于之前的两种方式,这里所有的I/O操作均采用完全异步的方式运行——既不会阻塞也不会轮询查询结果;相反地,它们会在后台由操作系统负责调度直至完成后通知用户态的应用代码。开发者只需定义好完成处理器(`CompletionHandler`)即可轻松捕获到最终的结果反馈信息[^1]. ```java AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(); serverChannel.bind(new InetSocketAddress(port)); serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() { @Override public void completed(AsynchronousSocketChannel result, Void attachment) { System.out.println("New connection accepted"); ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); result.read(buffer, buffer, new ReadCompletionHandler(result)); } @Override public void failed(Throwable exc, Void attachment) { logger.log(Level.SEVERE,"Failed to accept a connection",exc); } }); ``` ### 应用场景分析 - **低并发环境**: 如果业务需求较为单一且预计访问压力不大,那么可以选择简单的 BIO 方案快速搭建原型系统; - **中等规模并发负载**: 当面对一定数量级的同时在线用户数时,建议考虑基于 NIO 构建的服务架构,利用多路复用技术提升吞吐率; - **大规模分布式集群部署**: 在追求极致性能表现的情况下,尤其是涉及到海量短链接频繁交互或是长时间保持长连接通讯的任务场景,应该优先评估是否适合迁移到支持全异步语义的新一代 API —— 即 AIO 上面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值