BIO NIO AIO之間的區別

 

1、BIO、NIO、AIO的基本定義與類比描述:
BIO (Blocking I/O):同步阻塞I/O模式,數據的讀取寫入必須阻塞在一個線程內等待其完成。這裏使用那個經典的燒開水例子,這裏假設一個燒開水的場景,有一排水壺在燒開水,BIO的工做模式就是, 叫一個線程停留在一個水壺那,直到這個水壺燒開,纔去處理下一個水壺。可是實際上線程在等待水壺燒開的時間段什麼都沒有作。
NIO (New I/O):同時支持阻塞與非阻塞模式,但這裏咱們以其同步非阻塞I/O模式來講明,那麼什麼叫作同步非阻塞?若是還拿燒開水來講,NIO的作法是叫一個線程不斷的輪詢每一個水壺的狀態,看看是否有水壺的狀態發生了改變,從而進行下一步的操做。
AIO ( Asynchronous I/O):異步非阻塞I/O模型。異步非阻塞與同步非阻塞的區別在哪裏?異步非阻塞無需一個線程去輪詢全部IO操做的狀態改變,在相應的狀態改變後,系統會通知對應的線程來處理。對應到燒開水中就是,爲每一個水壺上面裝了一個開關,水燒開以後,水壺會自動通知我水燒開了
 
 
2、進程中的IO調用步驟大體能夠分爲如下四步:
1.進程向操做系統請求數據 ;
2.操做系統把外部數據加載到內核的緩衝區中;
3.操做系統把內核的緩衝區拷貝到進程的緩衝區 ;
4.進程得到數據完成本身的功能 ;
 
當操做系統在把外部數據放到進程緩衝區的這段時間(即上述的第二,三步),若是應用進程是掛起等待的,那麼就是同步IO,反之,就是異步IO,也就是AIO 。
 
3、各自的特色
1)BIO(Blocking I/O)同步阻塞I/O 
    會阻塞每個線程
 
    在高併發的web或者tcp服務器中採用BIO模型就沒法應對了,若是系統開闢成千上萬的線程,那麼CPU的執行時機都會浪費在線程的切換中,使得線程的執行效率大大下降。
 
2)NIO (New I/O) 同步非阻塞I/O 
    只阻塞一個線程
 
NIO是New I/O的簡稱,與舊式的基於流的I/O方法相對,從名字看,它表示新的一套Java I/O標 準。它是在Java 1.4中被歸入到JDK中的,並具備如下特性:
– NIO是基於塊(Block)的,它以塊爲基本單位處理數據
– 爲全部的原始類型提供(Buffer)緩存支持
– 增長通道(Channel)對象,做爲新的原始 I/O 抽象
– 支持鎖和內存映射文件的文件訪問接口
 – 提供了基於Selector的異步網絡I/O
 
關於NIO弄清除 Channel、Buffer、Selector三個類之間的關係就能夠了
 
Channel
首先說一下Channel,國內大多翻譯成「通道」。Channel和IO中的Stream(流)是差很少一個等級的。只不過Stream是單向的,譬如:InputStream, OutputStream。而Channel是雙向的,既能夠用來進行讀操做,又能夠用來進行寫操做,NIO中的Channel的主要實現有:FileChannel、DatagramChannel、SocketChannel、ServerSocketChannel;經過看名字就能夠猜出個因此然來:分別能夠對應文件IO、UDP和TCP(Server和Client)。
 
Buffer
NIO中的關鍵Buffer實現有:ByteBuffer、CharBuffer、DoubleBuffer、 FloatBuffer、IntBuffer、 LongBuffer,、ShortBuffer,分別對應基本數據類型: byte、char、double、 float、int、 long、 short。
 
Selector
Selector 是NIO相對於BIO實現多路複用的基礎,Selector 運行單線程處理多個 Channel,若是你的應用打開了多個通道,但每一個鏈接的流量都很低,使用 Selector 就會很方便。例如在一個聊天服務器中。要使用 Selector , 得向 Selector 註冊 Channel,而後調用它的 select() 方法。這個方法會一直阻塞到某個註冊的通道有事件就緒。一旦這個方法返回,線程就能夠處理這些事件,事件的例子有如新的鏈接進來、數據接收等。
 
 1 import java.io.IOException;
 2 import java.net.InetSocketAddress;
 3 import java.nio.channels.SelectionKey;
 4 import java.nio.channels.Selector;
 5 import java.nio.channels.ServerSocketChannel;
 6 import java.util.Iterator;
 7  
 8 public class TCPServerSelector{
 9     //緩衝區的長度
10     private static final int BUFSIZE = 256;
11     //select方法等待信道準備好的最長時間
12     private static final int TIMEOUT = 3000;
13     public static void main(String[] args) throws IOException {
14         if (args.length < 1){
15             throw new IllegalArgumentException("Parameter(s): <Port> ...");
16         }
17         //建立一個選擇器
18         Selector selector = Selector.open();
19         for (String arg : args){
20             //實例化一個信道
21             ServerSocketChannel listnChannel = ServerSocketChannel.open();
22             //將該信道綁定到指定端口
23             listnChannel.socket().bind(new InetSocketAddress(Integer.parseInt(arg)));
24             //配置信道爲非阻塞模式
25             listnChannel.configureBlocking(false);
26             //將選擇器註冊到各個信道
27             listnChannel.register(selector, SelectionKey.OP_ACCEPT);
28         }
29         //建立一個實現了協議接口的對象
30         TCPProtocol protocol = new EchoSelectorProtocol(BUFSIZE);
31         //不斷輪詢select方法,獲取準備好的信道所關聯的Key集
32         while (true){
33             //一直等待,直至有信道準備好了I/O操做
34             if (selector.select(TIMEOUT) == 0){
35                 //在等待信道準備的同時,也能夠異步地執行其餘任務,
36                 //這裏只是簡單地打印"."
37                 System.out.print(".");
38                 continue;
39             }
40             //獲取準備好的信道所關聯的Key集合的iterator實例
41             Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
42             //循環取得集合中的每一個鍵值
43             while (keyIter.hasNext()){
44                 SelectionKey key = keyIter.next();
45                 //若是服務端信道感興趣的I/O操做爲accept
46                 if (key.isAcceptable()){
47                     protocol.handleAccept(key);
48                 }
49                 //若是客戶端信道感興趣的I/O操做爲read
50                 if (key.isReadable()){
51                     protocol.handleRead(key);
52                 }
53                 //若是該鍵值有效,而且其對應的客戶端信道感興趣的I/O操做爲write
54                 if (key.isValid() && key.isWritable()) {
55                     protocol.handleWrite(key);
56                 }
57                 //這裏須要手動從鍵集中移除當前的key
58                 keyIter.remove();
59             }
60         }
61     }
62 }

 

 
3)AIO (Asynchronous I/O) 異步非阻塞I/O 
    不阻塞任何線程
 
  • 讀完了再通知我
  • 不會加快IO,只是在讀完後進行通知 
  • 使用回調函數,進行業務處理
 
 
 1 public static void main(String[] args) throws IOException {
 2  
 3     AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0000));
 4     server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
 5         final ByteBuffer buffer = ByteBuffer.allocate(1024);
 6  
 7         @Override
 8         public void completed(AsynchronousSocketChannel result, Object attachment) {
 9             System.out.println(Thread.currentThread().getName());
10             Future<Integer> writeResult = null;
11             try {
12                 buffer.clear();
13                 result.read(buffer).get(100, TimeUnit.SECONDS);
14                 buffer.flip();
15                 writeResult = result.write(buffer);
16             } catch (InterruptedException | ExecutionException e) {
17                 e.printStackTrace();
18             } catch (TimeoutException e) {
19                 e.printStackTrace();
20             } finally {
21                 try {
22                     server.accept(null, this);
23                     writeResult.get();
24                     result.close();
25                 } catch (Exception e) {
26                     System.out.println(e.toString());
27                 }
28             }
29         }
30  
31         @Override
32         public void failed(Throwable exc, Object attachment) {
33             System.out.println("failed: " + exc);
34         }
35     });
36  
37 }

 

 
 
 
你投入得越多,就能獲得越多得價值
相關文章
相關標籤/搜索