接上一篇《NIO.2特性總結(二)加強的通道 NetworkChannel》 java
We’ve finally reached the most powerful feature introduced in NIO.2, the asynchronous channel API. 多線程
我以爲第一個問題就是同步和異步的區別,The Difference Between Synchronous And Asynchronous。異步IO有時候也會叫overlapped I/O。這裏別跟阻塞和非阻塞混淆了。咱們這節主要說的是異步的問題,若是你不瞭解阻塞和非阻塞,你能夠看以前的文章,再羅嗦一點,異步和非阻塞不是一個東西。 app
同步I/O操做:In a synchronous I/O operation, a thread enters into action and waits until the I/O request is completed (the program is 「stuck」 waiting for the process to end, with no way out)。其實看這段我特別彆扭,怎麼看怎麼像阻塞的解釋。不過我在網上查到了這麼一段話:阻塞IO,非阻塞IO,IO複用,信號驅動IO,異步IO,前四種都屬於同步IO。這麼一看好像仍是那麼一回事兒。具體我還得去核實一下。 dom
異步I/O操做:When the same action occurs in an asynchronous environment, a thread performs the I/O operation with more kernel help. Actually, it immediately passes the request to the kernel and continues on to process another job. The kernel signals to the thread when the operation has completed, and the thread 「respects」 the signal by interrupting its current job and processing the data from the I/O operation as necessary。這個是否是又容易和Non-blocking混淆了,個人理解,異步操做會將任務直接交給內核,非阻塞雖然也返回,可是始終是在本身的線程上,他們之間的關係仍是看下面: 異步
網上也有不少例子,也有很多UML的圖來解釋這四個詞的含義,這個須要你們慢慢去體會,水仍是很深的。 socket
Java7中異步IO的實現是創建在兩件事情上: async
1. 在異步通道上獨立執行的線程(讀、寫、鏈接、關閉等)操做 this
2. 在操做初始化以後的控制機制 spa
Java7的異步IO操做有兩種form: .net
1. Pending Result:這個結果返回的是concurrent包中的Future對象。
2. Complete Result:採用CompleteHandler的回調機制返回結果。
咱們看異步通道全部的異步通道有須要遵循一個規則,在不阻塞應用去執行其餘任務的狀況下初始化IO操做和IO結束後的通知機制。在java7中有三個異步通道:AsynchronousFileChannel、AsynchronousSocketChannel和AsynchronousServerSocketChannel。另外還有一個比較重要的概念是group,要有組的概念是爲了把資源共享,每個異步的channel都會屬於一個group,同一個group裏的對象就能夠共享一個線程池。這個group由AsynchronousChannelGroup,實現。
接下來很少寫了,直接上代碼,仍是代碼容易理解,更多的代碼請看《pro java7 nio.2》,我只是摘了一部分:
異步文件:
package com.a2.nio2.chapter9.aio; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.concurrent.Future; public class AIOFileChannal { public static void main(String[] args) { ByteBuffer buffer = ByteBuffer.allocate(100); String encoding = System.getProperty("file.encoding"); Path path = Paths.get("C:/rafaelnadal/grandslam/RolandGarros", "story.txt"); try (AsynchronousFileChannel asynchronousFileChannel = AsynchronousFileChannel .open(path, StandardOpenOption.READ)) { Future<Integer> result = asynchronousFileChannel.read(buffer, 0); while (!result.isDone()) { System.out.println("Do something else while reading ..."); } System.out.println("Read done: " + result.isDone()); System.out.println("Bytes read: " + result.get()); } catch (Exception ex) { System.err.println(ex); } buffer.flip(); System.out.print(Charset.forName(encoding).decode(buffer)); buffer.clear(); } }異步socket,服務端:
package com.a2.nio2.chapter9.aio; import java.io.IOException; import java.net.InetSocketAddress; import java.net.StandardSocketOptions; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; public class EchoServer { public static void main(String[] args) { final int DEFAULT_PORT = 5555; final String IP = "127.0.0.1"; // create an asynchronous server socket channel bound to the default // group try (AsynchronousServerSocketChannel asynchronousServerSocketChannel = AsynchronousServerSocketChannel .open()) { if (asynchronousServerSocketChannel.isOpen()) { // set some options asynchronousServerSocketChannel.setOption( StandardSocketOptions.SO_RCVBUF, 4 * 1024); asynchronousServerSocketChannel.setOption( StandardSocketOptions.SO_REUSEADDR, true); // bind the asynchronous server socket channel to local address asynchronousServerSocketChannel.bind(new InetSocketAddress(IP, DEFAULT_PORT));// display a waiting message while ... // waiting clients System.out.println("Waiting for connections ..."); while (true) { Future<AsynchronousSocketChannel> asynchronousSocketChannelFuture = asynchronousServerSocketChannel .accept(); try (AsynchronousSocketChannel asynchronousSocketChannel = asynchronousSocketChannelFuture .get()) { System.out.println("Incoming connection from: " + asynchronousSocketChannel.getRemoteAddress()); final ByteBuffer buffer = ByteBuffer .allocateDirect(1024); // transmitting data while (asynchronousSocketChannel.read(buffer).get() != -1) { buffer.flip(); asynchronousSocketChannel.write(buffer).get(); if (buffer.hasRemaining()) { buffer.compact(); } else { buffer.clear(); } } System.out.println(asynchronousSocketChannel .getRemoteAddress() + " was successfully served!"); } catch (IOException | InterruptedException | ExecutionException ex) { System.err.println(ex); } } } else { System.out .println("The asynchronous server-socket channel cannot be opened!"); } } catch (IOException ex) { System.err.println(ex); } } }客戶端:
package com.a2.nio2.chapter9.aio; import java.io.IOException; import java.net.InetSocketAddress; import java.net.StandardSocketOptions; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.util.Random; import java.util.concurrent.ExecutionException; public class EchoClient { public static void main(String[] args) { final int DEFAULT_PORT = 5555; final String IP = "127.0.0.1"; ByteBuffer buffer = ByteBuffer.allocateDirect(1024); ByteBuffer helloBuffer = ByteBuffer.wrap("Hello !".getBytes()); ByteBuffer randomBuffer; CharBuffer charBuffer; Charset charset = Charset.defaultCharset(); CharsetDecoder decoder = charset.newDecoder(); // create an asynchronous socket channel bound to the default group try (AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel .open()) { if (asynchronousSocketChannel.isOpen()) { // set some options asynchronousSocketChannel.setOption( StandardSocketOptions.SO_RCVBUF, 128 * 1024); asynchronousSocketChannel.setOption( StandardSocketOptions.SO_SNDBUF, 128 * 1024); asynchronousSocketChannel.setOption( StandardSocketOptions.SO_KEEPALIVE, true); // connect this channel's socket Void connect = asynchronousSocketChannel.connect( new InetSocketAddress(IP, DEFAULT_PORT)).get(); if (connect == null) { System.out.println("Local address: " + asynchronousSocketChannel.getLocalAddress()); // transmitting data asynchronousSocketChannel.write(helloBuffer).get(); while (asynchronousSocketChannel.read(buffer).get() != -1) { buffer.flip(); charBuffer = decoder.decode(buffer); System.out.println(charBuffer.toString()); if (buffer.hasRemaining()) { buffer.compact(); } else { buffer.clear(); } int r = new Random().nextInt(100); if (r == 50) { System.out .println("50 was generated! Close the asynchronous socket channel!"); break; } else { randomBuffer = ByteBuffer.wrap("Random number:" .concat(String.valueOf(r)).getBytes()); asynchronousSocketChannel.write(randomBuffer).get(); } } } else { System.out.println("The connection cannot be established!"); } } else { System.out .println("The asynchronous socket channel cannot be opened!"); } } catch (IOException | InterruptedException | ExecutionException ex) { System.err.println(ex); } } }-------------------------------------------------------
其餘還有好比怎麼啓多線程去處理請求,怎麼操做group,書上都有就不貼出來了。這個還真須要點時間去研究研究。
固然還有個問題就是非阻塞怎麼和異步去結合,這個問題我也會抽空去研究一下。
後面的相關文章會補上NIO.2在文件系統操做上的新特性.