Java IO模型--边学边理解(二)

前言

前面已经学习了BIO以及NIO,本篇学习AIO。

2.3 AIO

       A即asynchronous,AIO即异步IO,前面学习的IO模型都是同步IO,回顾一下NIO,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。用户进程也需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,这种方式从用户进程的角度来看,是异步的,而数据在从内核在准备好后,拷贝到用户缓存的过程中,IO操作便是阻塞的,具体的IO操作(读写)还是由用户进程来完成,而AIO则是彻底的异步操作了,用户进程发起IO请求时,便立即返回,数据读写交给操作系统完成,读完了再通知java进程,用点外卖来举例,当我们点了一份螺蛳粉,使用NIO的方式则需要我们时不时的去看一下商家的制作进度,当制作完成了,我们就去拿,而AIO的方式,则只需要我们简单的下单,做好了送上门来。

示例

服务器端:server中使用的通道是AsynchronousServerSocketChannel,这个类提供了一个open()静态工厂,一个bind()方法用于绑定服务端IP地址(还有端口号),另外还提供了accept()用于接收用户连接请求。

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.Future;
import java.util.concurrent.TimeUnit;

/**
 * @author jhz
 * @date 18-10-8 下午10:12
 */
public class AIOServer {
    private final int port;
    private final String IP;
    private AsynchronousServerSocketChannel server = null;

    public AIOServer(int port,String IP) {
        this.port = port;
        this.IP = IP;
        try {
            //产生一个异步通道AsynchronousServerSocketChannel
            server = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(IP,port));
        } catch (Exception e){
          e.printStackTrace();
        }
    }

    //使用server来接受并处理客户端消息
    public void start(){
        System.out.println("开始监听端口:" + port);

        //定义IO操作完成后的处理器
        server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
            final ByteBuffer buffer = ByteBuffer.allocate(1024);

            //重写完成事件回调方法
            @Override
            public void completed(AsynchronousSocketChannel result, Object attachment) {
                System.out.println(Thread.currentThread().getName());
                Future<Integer> writeResult = null;
                try {
                    buffer.clear();
                    result.read(buffer).get(100, TimeUnit.SECONDS);
                    System.out.println("接收到数据:" + new String(buffer.array()));
                    //翻转缓冲区
                    buffer.flip();
                    //发送消息给客户端
                    writeResult = result.write(buffer);
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    try {
                        server.accept(null,this);
                        writeResult.get();
                        result.close();
                    }catch (Exception e){
                        e.printStackTrace();
                    }

                }
            }

            @Override
            public void failed(Throwable exc, Object attachment) {
                System.out.println("failed:" + exc);
            }
        });
    }

    public static void main(String[] args) {
        new AIOServer(12345,"localhost").start();
        while (true){
            try {
                Thread.sleep(1000);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

}

客户端使用的通道是:AsynchronousSocketChannel,这个通道处理提供open静态工厂方法外,还提供了read和write方法。

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;

/**
 * @author jhz
 * @date 18-10-8 下午10:39
 */
public class AIOClient {
    public static void main(String[] args) throws IOException {
        AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
        InetSocketAddress serverAddress = new InetSocketAddress("localhost",12345);

        CompletionHandler<Void,? super Object> handler = new CompletionHandler<Void, Object>() {
            //客户端定义为一个发送接收hello消息的handler,连接成功后,在complete中将hello写入缓冲区,并发送到客户端,接收到
            //服务器返回后,在第二个complete中读取缓冲区的数据,读取完成后在第三个complete中关闭连接
            @Override
            public void completed(Void result, Object attachment) {
                client.write(ByteBuffer.wrap("hello".getBytes()), null, new CompletionHandler<Integer, Object>() {
                    @Override
                    public void completed(Integer result, Object attachment) {
                        final ByteBuffer buffer = ByteBuffer.allocate(1024);
                        client.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
                            @Override
                            public void completed(Integer result, ByteBuffer attachment) {
                                buffer.flip();
                                System.out.println("客户端接收到消息:" + new String(buffer.array()));
                                try {
                                    client.close();
                                }catch (Exception e){
                                    e.printStackTrace();
                                }
                            }

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

                            }
                        });
                    }

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

                    }
                });
            }

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

            }
        };
        client.connect(serverAddress,null,handler);
        try {
            Thread.sleep(1000);
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

测试

小结

由于NIO的读写过程依然在应用线程里完成,所以对于那些读写过程时间长的,NIO就不太适合。而AIO的读写过程完成后才被通知,所以AIO能够胜任那些重量级,读写过程长的任务。在IO吞吐量上AIO是要高于NIO的,但在Linux系统中,底层的实现都是使用epoll,因此IO性能上没什么区别,个人觉得如果是较为轻量级且频繁的IO操作,还是使用Netty更为灵活且可定制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值