java中IO模型-AIO模型

AIO模型介绍

AIO(Asynchronous I/O) 异步非阻塞模型, 在javajdk.17版本开始支持AIO,AIO模型需要操作系统的支持。
AIO最大的特性是异步能力,对socket和I/O起作用。
java中IO模型-AIO模型
异步IO模型类似的
与NIO模型不同,读写操作为例,只需直接调用read和write的API即可,这方法都是异步的。
对于读操作:当有流可读是,系统会将可读的流传入到read方法的缓冲区,并通知应用程序。
读写都是异步的,完成之后会主动调用回调函数。

在JDK 1.7中,nio.2,主要在java.nio.channels包下新增了四个异步通道AsynchronousSocketChannel:异步操作TCP通道,主要连接AsynchronousServerSocketChannel,一般在客户端实现。
AsynchronousServerSocketChannel:异步操作TCP通道,主要接收客户端的连接,一般在服务端实现。
AsynchronousFileChannel:操作文件的。
AsynchronousDatagramChanel:异步操作UDP的通道。

AsynchronousServerSocketChannel:AIO中网络通信服务端的socket

AIO中实现方法,以accept方法为例
由于异步IO实际IO操作是交给操作系统来做,应用程序只负责同志操作系统进行IO和接口操作系统IO完成的通知,所以异步的accept的方法调用是不会阻塞的。

异步IO中有两种实现方式:

1、future方法

Future accept();

提交一个IO操作请求(Accept/read/write),返回future,就可以对future进行检车,future.get()方法,future方法会让用户程序阻塞直至操作正常完成,使用future方法比较简单,但是future.get()是同步的,使用该方式恒荣进入到同步的编程模式,这种让是会是AIO的异步操作成为摆设。

2、callback回调方式

void accept(A attachment, CompletionHandler<AsynchronousSocketChannel,? super A> handler)

开始接收客户端的连接,连接成功或者失败都是触发CompletionHandler对象的响应方法,
CompletionHandler接口提供了两个方法:
void completed(V result, A attachment);当IO完成时触发该方法,该方法的第一个参数代表IO操作的返回的对象,第二个参数代表发起IO操作时传入的附加参数
void failed(Throwable exc, A attachment);当IO失败是触发的该方法,第一个参数表示IO操作失败引引起的异常或者是错误。

即提交一个IO操作请求(Accept/read/write),指定一个CompletionHandler,当异步IO操作完成时,发送一个通知,这个时候CompletionHandler对象的completed或者failed方法将会被调用。

AIO的实现需要充分调用操作系统参数,IO需要操作系统的支持,并发也同样需要操作系统的支持,所以性能方面不同的操作系统差异会比较明显。

AIO 的回调方式编程

/**
 * desc:AIO服务端代码
 * @user:西财彭于晏
 * @date:2021/9/22
 */

public class Server {
    public static void main(String[] args) {
        try {
            //创建服务端通道
            AsynchronousServerSocketChannel asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open();

            //绑定端口
            asynchronousServerSocketChannel.bind(new InetSocketAddress(6666));
            System.out.println("服务端启动");


            //接收客户端连接 accept 接收操作是异步操作
            asynchronousServerSocketChannel.accept(null, new AcceptComplationHandler(asynchronousServerSocketChannel));
            //BIO accept操作返回Socket实例  Socket socket= serversocket.accept();
            //AIO accept操作返回AsynchronousSocketChannel

            //accept是异步操作,防止当前程序直接执行结束
            //方法1:while(true)+sleep
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

/**
 * desc:接收连接accept的回调
 * //BIO accept操作返回Socket实例  Socket socket= serversocket.accept();
 * //AIO accept操作返回AsynchronousSocketChannel
 * @user:西财彭于晏
 * @date:2021/9/22
 */

public class AcceptComplationHandler implements CompletionHandler<AsynchronousSocketChannel,Object> {
    private AsynchronousServerSocketChannel channel;
    public AcceptComplationHandler(AsynchronousServerSocketChannel channel) {
        this.channel = channel;
    }


    @Override
    public void completed(AsynchronousSocketChannel result, Object attachment) {
        System.out.println("有新客户的连接");
        //完成accept连接IO操作
        //读写操作,需要使用Buffer,和NIO比较,当前AIO称之为NIO.2
        //创建新的buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //读客户端数据,读操作是异步操作,需要实现CompletionHandler对象
        /**
         * <A> void read(ByteBuffer dst,A attachment,CompletionHandler<Integer,? super A> handler);
         * 读操作异步方式方法解读
         * 第一个参数:dst  数据读取的目的地
         * 第二个参数:attachment  给读回调传递的额外信息
         * 第三个参数:CompletionHandler 当读数据完成后CompletionHandler对象
         */
        result.read(byteBuffer,byteBuffer,new ReadCompletionHandler(result));

        //再次接收其他的客户端连接的
        channel.accept(null,new AcceptComplationHandler(channel));

    }

    @Override
    public void failed(Throwable exc, Object attachment) {

    }
}

/**
 * desc:AIo的读操作的回调
 * 读操作的结果为读取的数据的个数
 * @user:西财彭于晏
 * @date:2021/9/22
 */

public class ReadCompletionHandler implements CompletionHandler<Integer,ByteBuffer> {
    //用户接受或者发送操作的channel
    private AsynchronousSocketChannel asynchronousSocketChannel;

    public ReadCompletionHandler(AsynchronousSocketChannel channel) {
        this.asynchronousSocketChannel = channel;
    }

    @Override
    public void completed(Integer result, ByteBuffer attachment) {
        //读数据完成后
        //数据已经完成并写入到ByteBuffer类型的变量result
        attachment.flip();
        byte[] bytes = new byte[attachment.remaining()];
        attachment.get(bytes);
        String msg = null;
        try {
            msg = new String(bytes,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println("服务端接收数据:"+msg);
        attachment.clear();

        //重复接收消息,再次调用异步读操作
        this.asynchronousSocketChannel.read(attachment,attachment,new ReadCompletionHandler(this.asynchronousSocketChannel));


    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {

    }
}
  //创建异步通道实例
            AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open();

            //连接服务端,异步方式
            asynchronousSocketChannel.connect(new InetSocketAddress("127.0.0.1",6666),asynchronousSocketChannel,new ConnetionComplateHandler());

            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

            //写操作
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNext()) {
                String msg = scanner.nextLine();
                if (msg != null && !"".equals(msg.trim())) {
                    byteBuffer.put(msg.getBytes());
                    byteBuffer.flip();
                    asynchronousSocketChannel.write(byteBuffer);
                    byteBuffer.clear();
                }
            }


        } catch (IOException e) {
            e.printStackTrace();
        }

public class ConnetionComplateHandler implements CompletionHandler<Void,AsynchronousSocketChannel> {
    @Override
    public void completed(Void result, AsynchronousSocketChannel attachment) {
        //连接服务端成功
        System.out.println("连接服务端成功");
    }

    @Override
    public void failed(Throwable exc, AsynchronousSocketChannel attachment) {

    }
}

BIO、NIO、AIO的比较

java中IO模型-AIO模型

1、释义

BIO:同步阻塞IO模型

在JDK1.4之前网络通信使用的都是BIO模型,BIO模型中accept()、read()、write()、Connection()都会阻塞,BIO要同时支处理多个客户端的连接,就必须使用多线程,即每次accept阻塞等待客户端连接对象socket,为每一个socket创建一个线程。
采用多线程范式使得BIO具备了高并发能力,即同时处理多客户端连接请求,但带来新问题,随着开启线程数量增多,会消耗过多的内存资源,导致服务器变慢甚至崩溃。

NIO:同步非阻塞IO模型

采用了事件驱动的思想实现了一个多路复用器,由复用器来同时监听多个事件是否准备就绪。
一个selector复用器同时可以监听多个客户端的连接及IO操作,一个selector复用器只需要一个线程处理即可,即NIO能实现一个线程来管理多个客户端连接,NIO主要处理的是有效的连接。

AIO:异步非阻塞IO模型

在JDK1.7之后提供了异步的相关通道实例,AIO提供的最大的特点是具备异步功能,需要借助操作系统,底层操作系统具有异步IO模型,
异步操作的实现是在对应的read/write/accept/connection等方法异步执行,完成后会主动调用回调函数,实现一个CompletionHandler对象。

应用场景

BIO:BIO方式适用于连接数量少且固定的场景,这种方式对服务器资源要求比较高, JDK1.4之前唯一的选择,程序直观简单易理解。
NIO:适用于连接数目多且业务比较轻,比如:聊天服务器 JDK1.4开始支持NIO。
AIO:适用于连接数目多且连接比较长(业务重操作),需要操作系统充分参与并发操作 JDK1.7开始支持。

上一篇:BIO/NIO/AIO


下一篇:Docker安装mysql将data数据目录挂载到本地磁盘