当前位置: 首页 > news >正文

Java学习-----AIO模型

        在 Java 的 I/O 模型中,AIO(Asynchronous I/O,异步 I/O)是继 BIO、NIO 之后的又一大作。它以 “异步非阻塞” 的特性,为高并发场景提供了更高效的处理方式,尤其在需要应对大量并发连接且 I/O 操作耗时较长的场景中表现突出。

        AIO 的核心在于异步非阻塞,其采用 “回调通知” 的模式,即当 I/O 操作完成后,系统会自动通知应用程序进行后续处理,无需线程主动轮询。AIO 主要依靠异步通道(AsynchronousChannel)和完成处理器(CompletionHandler)这两个核心组件实现,具体原理如下:​

(1)异步通道(AsynchronousChannel):与 NIO 中的通道类似,异步通道是数据传输的通道,但它支持异步操作。常见的异步通道有AsynchronousServerSocketChannel(用于服务器端监听连接)、AsynchronousSocketChannel(用于客户端与服务器端的通信)等。​

(2)完成处理器(CompletionHandler):这是 AIO 实现异步回调的关键。当异步 I/O 操作(如连接、读取、写入等)完成后,系统会自动调用CompletionHandler中的回调方法,应用程序在该方法中处理操作结果。CompletionHandler有两个核心方法:completed(操作成功完成时调用)和failed(操作失败时调用)。​

        其工作流程大致为:服务器端通过AsynchronousServerSocketChannel监听端口,调用accept方法并传入CompletionHandler。当客户端发起连接请求时,系统会异步处理连接操作,连接完成后调用CompletionHandler的completed方法,在该方法中可以获取客户端的AsynchronousSocketChannel。随后,通过该通道进行异步的读写操作,同样传入CompletionHandler,当读写操作完成后,系统会调用相应的回调方法进行处理。​

        作为继BIO和NIO之后的I/O模型,AIO有着许多相较于前面二者都没有的优点,如:​

(1)真正的异步非阻塞:AIO 不需要线程主动轮询 I/O 操作的状态,而是由操作系统完成后通知应用程序,极大地减少了线程的空闲等待时间,提高了线程的利用率。​

(2)适合处理耗时较长的 I/O 操作:对于文件读写、网络通信等耗时较长的 I/O 操作,AIO 能让线程在操作期间去处理其他任务,避免线程阻塞,提升系统的整体吞吐量。​

(3)编程模型更简洁:相比 NIO 的多路复用模式,AIO 通过回调机制处理 I/O 结果,代码逻辑更清晰,减少了对选择器等组件的依赖。​

        但同时,其也有不少缺点,如:​

(1)操作系统支持有限:AIO 的实现依赖于操作系统的异步 I/O 支持,不同操作系统对异步 I/O 的支持程度不同,可能会影响 AIO 的性能表现和跨平台性。​

(2)在低延迟场景下优势不明显:对于一些 I/O 操作耗时很短的场景,AIO 的异步处理机制带来的开销可能超过其优势,此时 NIO 甚至 BIO 可能更合适。​

(3)调试和排查问题较复杂:由于异步操作的回调执行顺序不确定,当出现问题时,调试和排查的难度相对较大。​

        还是一样,下面通过一个简单的客户端 - 服务器通信示例来展示 Java AIO 的使用。​

服务器端代码​

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;public class AioServer {public static void main(String[] args) throws IOException {// 创建异步服务器通道并绑定端口AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8888));System.out.println("服务器启动,监听端口8888...");// 接受客户端连接serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {@Overridepublic void completed(AsynchronousSocketChannel socketChannel, Void attachment) {// 继续接受其他客户端连接serverSocketChannel.accept(null, this);try {System.out.println("收到新的客户端连接:" + socketChannel.getRemoteAddress());// 读取客户端发送的数据ByteBuffer buffer = ByteBuffer.allocate(1024);socketChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer bytesRead, ByteBuffer buffer) {if (bytesRead > 0) {buffer.flip();byte[] data = new byte[buffer.remaining()];buffer.get(data);String message = new String(data);System.out.println("收到客户端消息:" + message);// 向客户端发送响应String response = "服务器已收到消息:" + message;ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());socketChannel.write(responseBuffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesWritten, Void attachment) {System.out.println("向客户端发送响应完成");try {socketChannel.close();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void failed(Throwable exc, Void attachment) {System.out.println("向客户端发送响应失败:" + exc.getMessage());try {socketChannel.close();} catch (IOException e) {e.printStackTrace();}}});} else if (bytesRead == -1) {// 客户端关闭连接try {socketChannel.close();System.out.println("客户端连接关闭");} catch (IOException e) {e.printStackTrace();}}}@Overridepublic void failed(Throwable exc, ByteBuffer buffer) {System.out.println("读取客户端数据失败:" + exc.getMessage());try {socketChannel.close();} catch (IOException e) {e.printStackTrace();}}});} catch (IOException e) {e.printStackTrace();}}@Overridepublic void failed(Throwable exc, Void attachment) {System.out.println("接受客户端连接失败:" + exc.getMessage());}});// 防止服务器退出try {Thread.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();}}
}
/*创建AsynchronousServerSocketChannel并绑定端口,调用accept方法并传入CompletionHandler。当客户端连接完成后,completed方法被调用,在该方法中继续接受其他客户端连接,然后通过AsynchronousSocketChannel的read方法异步读取客户端数据,读取完成后在回调方法中处理数据,并通过write方法异步向客户端发送响应,最后关闭通道。若操作失败,failed方法会被调用并处理异常。
*/

客户端代码​

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;public class AioClient {public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {// 打开异步客户端通道并连接服务器AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();Future<Void> future = socketChannel.connect(new InetSocketAddress("localhost", 8888));future.get(); // 等待连接完成System.out.println("已连接到服务器");// 向服务器发送数据Scanner scanner = new Scanner(System.in);System.out.println("请输入要发送的消息:");String message = scanner.nextLine();ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());Future<Integer> writeFuture = socketChannel.write(buffer);writeFuture.get(); // 等待写入完成// 读取服务器的响应buffer.clear();Future<Integer> readFuture = socketChannel.read(buffer);int bytesRead = readFuture.get(); // 等待读取完成if (bytesRead > 0) {buffer.flip();byte[] data = new byte[buffer.remaining()];buffer.get(data);String response = new String(data);System.out.println("收到服务器响应:" + response);}scanner.close();socketChannel.close();System.out.println("客户端连接关闭");}
}
/*创建AsynchronousSocketChannel,通过connect方法连接服务器,使用Future等待连接完成。然后向服务器发送数据,同样通过Future等待写入完成。之后读取服务器的响应,最后关闭通道。客户端代码中同时展示了使用Future和回调两种方式处理异步操作的结果,其中Future方式更适合简单场景,回调方式则更符合 AIO 的异步特性。
*/

        从代码中可以清晰地看到 AIO 的异步非阻塞特性,所有 I/O 操作都是异步进行的,线程无需主动等待操作完成,而是通过回调或Future获取操作结果,极大地提高了线程的利用效率。​

http://www.lryc.cn/news/595453.html

相关文章:

  • 2025杭电多校赛(2)1006 半
  • 对称加密技术详解:原理、算法与实际应用
  • 代码随想录算法训练营二十二天|回溯part04
  • 关于线程的例子
  • 【力扣】第42题:接雨水
  • 复制docker根目录遇到的权限问题
  • 模拟高负载测试脚本
  • 闲庭信步使用图像验证平台加速FPGA的开发:第二十八课——图像膨胀的FPGA实现
  • 关于Ajax的学习笔记
  • Linux的相关指令
  • 「日拱一码」034 机器学习——插值处理
  • Unity 脚本生命周期详解与实战分析
  • (十九)深入了解 AVFoundation-编辑:使用 AVMutableVideoComposition 实现视频加水印与图层合成(上)——理论篇
  • iOS 加固工具有哪些?快速发布团队的实战方案
  • RIQ模型时间管理方法详解
  • 工业自动化中的协议转换:RS485转PROFIBUS网关在涡街流量计与S7-300 PLC通信中的应用
  • Swap Face 使用遇到的问题
  • Match宣布2025曼谷发布会,发布“保本”资管新范式,旨在重塑Web3投资规则
  • 20250720问答课题-基于BERT与混合检索问答系统代码解读
  • 企业开发转型 | 前端AI化数字化自动化现状
  • 自动化商品监控:利用淘宝API开发实时价格库存采集接口
  • 【unitrix】 6.11 二进制数字标准化模块(normalize.rs)
  • G7打卡——Semi-Supervised GAN
  • Acrobat JavaScript 中的 `app.response()` 方法
  • 【学习路线】C#企业级开发之路:从基础语法到云原生应用
  • 基于MySQL实现分布式调度系统的选举算法
  • 一文速通《矩阵的特征值和特征向量》
  • Tomcat的部署、单体架构、session会话、spring
  • PostgreSQL高可用架构Repmgr部署流程
  • 计算机网络中:传输层和网络层之间是如何配合的