多线程笔记 - 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权威指南