AIO需要操作系統的支持,在linux內核2.6版本中加入了對真正異步IO的支持,java從jdk1.7開始支持AIO
核心類有AsynchronousSocketChannel 、AsynchronousServerSocketChannel、AsynchronousChannelGroup
前兩個個類是javaAIO為TCP通信提供的異步Channel。看名字就知道應該是干什么的了。
創建AsynchronousServerSocketChannel的代碼如下:
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(PORT));
其中open()有一個重載方法,可以使用指定的AsynchronousChannelGroup來創建AsynchronousServerSocketChannel。
AsynchronousChannelGroup是異步Channel的分組管理器,它可以實現資源共享。創建AsynchronousChannelGroup時,需要傳入一個ExecutorService,也就是綁定一個線程池,該線程池負責兩個任務:處理IO事件和觸發CompletionHandler回調接口。代碼如下:
AsynchronousServerSocketChannel serverSocketChannel = null; try { ExecutorService executorService = Executors.newFixedThreadPool(80); AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executorService); serverSocketChannel = AsynchronousServerSocketChannel.open(channelGroup).bind(new InetSocketAddress(9000)); }catch (IOException ioe){ ioe.printStackTrace(); }
AsynchronousServerSocketChannel創建成功后,類似於ServerSocket,也是調用accept()方法來接受來自客戶端的連接,由於異步IO實際的IO操作是交給操作系統來做的,用戶進程只負責通知操作系統進行IO和接受操作系統IO完成的通知。所以異步的ServerChannel調用accept()方法后,當前線程不會阻塞,程序也不知道accept()方法什么時候能夠接收到客戶端請求並且操作系統完成網絡IO,為解決這個問題,AIO為accept方法提供兩個版本:
Future<AsynchronousSocketChannel> accept() :開始接收客戶端請求,如果當前線程需要進行網絡IO(即獲得AsynchronousSocketChannel),則應該調用該方法返回的Future對象的get()方法,但是get方法會阻塞該線程,所以這種方式是阻塞式的異步IO。
<A> void accept(A attachment ,CompletionHandler<AsynchronousSocketChannel,? super A> handler):開始接受來自客戶端請求,連接成功或失敗都會觸發CompletionHandler對象的相應方法。其中AsynchronousSocketChannel就代表該CompletionHandler處理器在處理連接成功時的result是AsynchronousSocketChannel的實例。
而CompletionHandler接口中定義了兩個方法,
completed(V result , A attachment):當IO完成時觸發該方法,該方法的第一個參數代表IO操作返回的對象,第二個參數代表發起IO操作時傳入的附加參數。
faild(Throwable exc, A attachment):當IO失敗時觸發該方法,第一個參數代表IO操作失敗引發的異常或錯誤。
使用第一種accept方法需要如下代碼
while (true){ Future<AsynchronousSocketChannel> future = serverSocketChannel.accept(); AsynchronousSocketChannel socketChannel = null; try { socketChannel = future.get(); socketChannel.write(ByteBuffer.wrap("ssss".getBytes("UTF-8"))); }catch (Exception e){ e.printStackTrace(); } }
通常使用第二種accept,實現自己的CompletionHandler實現類。
而AsynchronousSocketChannel的的用法與Socket類似,由三個方法,但是不同的是每個方法又分為Future版本與CompletionHandler版本。
connect():用於連接到指定端口,指定IP地址的服務器
read()、write():完成讀寫。
注意!使用異步Channel時,accept()、connect()、read()、write()等方法都不會阻塞,也就是說如果使用返回Future的這些方法,程序並不能直到什么時候成功IO,必須要使用get方法,等get方法的阻塞結束后才能確保IO完成,繼續執行下面的操作。