多线程笔记 - AIO

AIO是异步非阻塞io, 也叫 nio2.0.

直接上代码,

server:

public class Server implements Runnable {

    public AsynchronousServerSocketChannel assc;

    private CountDownLatch latch;

    public Server(int port) {
        try {
            assc = AsynchronousServerSocketChannel.open();
            assc.bind(new InetSocketAddress(port));
            System.out.println("服务器启动 : " + port);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        latch = new CountDownLatch(1);

        assc.accept(this, new ServerCompletionHandler());

        try {
            latch.await();
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        new Thread(new Server(1234)).start();
    }
}

ServerCompletionHandler 是一个回调类, 里面封装了连接成功后的回调方法:
public class ServerCompletionHandler   implements CompletionHandler<AsynchronousSocketChannel, Server> {
    @Override
    public void completed(AsynchronousSocketChannel asc, Server attachment) {
        //当有下一个客户端接入的时候 直接调用Server的accept方法,
        // 这样反复执行下去,保证多个客户端都可以阻塞
        attachment.assc.accept(attachment, this);
        read(asc);
    }

    private void read(final AsynchronousSocketChannel asc) {
        //读取数据
        ByteBuffer buf = ByteBuffer.allocate(1024);
        asc.read(buf, buf, new CompletionHandler<Integer, ByteBuffer>() {
            @Override
            public void completed(Integer resultSize, ByteBuffer attachment) {
                //进行读取之后,重置标识位
                attachment.flip();
                //获得读取的字节数
                System.out.println("Server -> " + "收到客户端的数据长度为:" + resultSize);
                //获取读取的数据
                String resultData = new String(attachment.array()).trim();
                System.out.println("Server -> " + "收到客户端的数据信息为:" + resultData);
                String response = "服务器响应, 收到了客户端发来的数据: " + resultData;
                write(asc, response);
            }
            @Override
            public void failed(Throwable exc, ByteBuffer attachment) {
                exc.printStackTrace();
            }
        });
    }

    private void write(AsynchronousSocketChannel asc, String response) {
        try {
            ByteBuffer buf = ByteBuffer.allocate(1024);
            buf.put(response.getBytes());
            buf.flip();
            asc.write(buf).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void failed(Throwable exc, Server attachment) {
        exc.printStackTrace();
    }
}

 

客户端:

public class ClientA implements Runnable{

    private AsynchronousSocketChannel asc ;

    private CountDownLatch latch = new CountDownLatch(1);

    public ClientA(){
        try {
            asc = AsynchronousSocketChannel.open();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void connect(){
        //与服务器建立连接
        asc.connect(new InetSocketAddress("127.0.0.1", 1234));
    }

    public void read(){
        ByteBuffer buf = ByteBuffer.allocate(1024);
        try {
            asc.read(buf).get();
            buf.flip();
            byte[] respByte = new byte[buf.remaining()];
            buf.get(respByte);
            System.out.println(new String(respByte,"utf-8").trim());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    public void write(String request){
        try {
            asc.write(ByteBuffer.wrap(request.getBytes())).get();
            read();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            //让线程不退出
            latch.await();
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        ClientA c1 = new ClientA();
        c1.connect();

        ClientA c2 = new ClientA();
        c2.connect();

        ClientA c3 = new ClientA();
        c3.connect();

        new Thread(c1, "c1").start();
        new Thread(c2, "c2").start();
        new Thread(c3, "c3").start();

        Thread.sleep(1000);

        c1.write("c1 aaa");
        c2.write("c2 bbbb");
        c3.write("c3 ccccc");
    }
}

 

结果:

client: 

 

server: 

 

 各种io比较表:

  同步阻塞(BIO) 伪异步IO 同步非阻塞(NIO) 异步非阻塞(AIO)
客户端个数: I/O线程 1:1

M:N

(M可大于N)

M:1 

(1个I/O线程处理

多个客户端连接)

M:0

(不需要启动额外的I/O线程

,被动回调)

I/O类型(阻塞) 阻塞I/O 阻塞I/O 非阻塞I/O 非阻塞I/O
I/O类型(同步) 同步I/O 同步I/O

同步I/O

(I/O多路复用)

异步I/O
API使用难度 简单 简单 非常复杂 复杂
调试难度 简单 简单 复杂 复杂
可靠性 非常差
吞吐量

 

参考:
  Netty权威指南

 

posted @ 2020-03-01 15:31  Sniper_ZL  阅读(479)  评论(0编辑  收藏  举报