詳解NIO、BIO、AIO

1.阻塞和非阻塞java

阻塞和非阻塞是進程在訪問數據的時候,進程需不須要等待。linux

1. 阻塞api

當數據沒有準備好時,都會一直等待緩衝區中的數據準備就緒以後纔會開始處理,不然會一直等待下去。數組

2. 非阻塞安全

當進程訪問到數據緩衝區時,若是數據還未準備好,會直接返回不會一直等待,若是數據已經準備好了,也會直接返回。服務器

2.同步和異步網絡

同步和異步都是基於應用程序和操做系統處理IO事件鎖採用的方式。併發

同步:框架

  1. 同步是應用系統直接參與IO讀寫操做。在處理IO事件的時候必須阻塞在某個方法上面等待IO事件完成(阻塞IO事件或則經過輪詢IO事件的方式)。異步

  2. 阻塞IO實現方式,通常是直接阻塞到read和write方法。都是將讀(寫)方法交給線程來操做,而後阻塞線程的方式來實現,只是這樣對線程開銷較大。

異步:

  1. 異步是全部的IO讀寫都交給了操做系統,這個時候就能夠去作其它的事情並不須要去完成真正的IO操做,當操做完成IO後,系統將會給的應用程序一個通知的。

3.Java IO模型,NIO,BIO,AIO

NIO:

jdk1.4 linux多路複用技術 (select模式)實現IO事件的輪詢方式同步非阻塞的模式,這種方式目前是主流的網絡通訊模式。

目前市面上的這種模式的框架有:Mina, netty,mina2.0,nett5.0--網絡通訊框架比直接寫

NIO要容易些,而且代碼可讀性更好。

BIO:

JDK1.4之前使用都是BIO阻塞IO,主要是阻塞到線程來操做的,但對於線程的開銷原本就是性能的浪費。

AIO:

jdk1.7(NIO2)纔是實現真正的異步aio,學習 它的思想主要是借鑑了linux epoll模式。

4.NIO的原理

先來看一張圖
詳解NIO、BIO、AIO

網絡通訊中,NIO也提供了SocketChannel和ServerSocketChannel兩種不一樣的套接字通道來實現,這兩個類都實現了Channel接口。它們能夠設置阻塞與非阻塞兩種模式,爲了實現高負載高併發都採起非阻塞的模式。

NIO採用緩衝區Buffer,實現對數據的讀寫操做,緩衝區是固定大小,並由內部狀態記錄有多少數據被放入或者取出。

與阻塞IO不一樣,阻塞IO採用阻塞式流(Stream)的方式進行讀寫,流是單向的只能向一個方向讀數據或者寫數據。

而通道是雙向的,能夠同時在通道上發送和讀取數據,並且是非阻塞的,在沒有數據可讀可寫時能夠去作別的事情。

主要使用了ServerSocketChannel,SocketChannel,Selector,ByteBuffer這麼幾個類。

1.ServerSocketChannel(服務端使用類)

採用api文檔解釋:經過調用此類的 open 方法建立服務器套接字通道。新建立的服務器套接字通道已打開,但還沒有綁定。

試圖調用未綁定的服務器套接字通道的 accept 方法會致使拋出 NotYetBoundException。

可經過調用相關服務器套接字的某個 bind 方法來綁定服務器套接字通道。多個併發線程可安全地使用服務器套接字通道。

2.SocketChannel(客戶端使用類)

採用api文檔解釋:經過調用此類的某個 open 方法建立套接字通道。

新建立的套接字通道已打開,但還沒有鏈接。試圖在未鏈接的通道上調用 I/O 操做將致使拋出 NotYetConnectedException。

可經過調用套接字通道的 connect 方法鏈接該通道;一旦鏈接後,關閉套接字通道以前它會一直保持已鏈接狀態。

可經過調用套接字通道的 isConnected 方法來肯定套接字通道是否已鏈接。

3. Selector(選擇器):

是 SelectableChannle 對象的多路複用器,Selector 能夠同時監控多個 SelectableChannel 的 IO 情況,也就是說,利用 Selector可以使一個單獨的線程管理多個 Channel,selector 是非阻塞 IO 的核心。

當通道使用register(Selector sel, int ops)方法將通道註冊選擇器時,選擇器對通道事件進行監聽,經過第二個參數指定監聽的事件類型。

其中可監聽的事件類型包括如下:

讀 : SelectionKey.OP_READ (1)

寫 : SelectionKey.OP_WRITE (4)

鏈接 : SelectionKey.OP_CONNECT (8)

接收 : SelectionKey.OP_ACCEPT (16)

若是須要監聽多個事件是:

int key = SelectionKey.OP_READ | SelectionKey.OP_WRITE ; //表示同時監聽讀寫操做。

4.Bytebuffer

ByteBuffer類是Buffer的子類,Buffer是頂層抽象類,ByteBuffer繼承Buffer,也是抽象類。看看繼承結構。

詳解NIO、BIO、AIO

ByteBuffer是在javaNIO中常使用的一個緩衝區類,使用ByteBuffer能夠進行高效的IO操做。經過 ByteBuffer提供不少讀寫的方法put(),get(),而且還包含四個很重要的屬性。

容量(capacity)

capacity指的是緩衝區可以容納元素的最大數量,這個值在緩衝區建立時被設定,並且不可以改變,以下,咱們建立了一個最大容量爲10的字節緩衝區;

ByteBuffer bf = ByteBuffer.allocate(10);
上界(limit)

limit指的是緩衝區中第一個不能讀寫的元素的數組下標索引,也能夠認爲是緩衝區中實際元素的數量;

位置(position)

position指的是下一個要被讀寫的元素的數組下標索引,該值會隨get()和put()的調用自動更新;

標記(mark)

一個備忘位置,調用mark()方法的話,mark值將存儲當前position的值,等下次調用reset()方法時,會設定position的值爲以前的標記值;

四個屬性值之間的關係

根據以上四個屬性的定義,咱們能夠總結出它們之間的關係以下:

0 <= mark <= position <= limit <= capacity

5.NIO操做流程

  1. 服務端對象:ServerSocketChannel

  2. 客戶端對象:SocketChannel

  3. 選擇器:Selector selector= Selector.open();//這樣就打開了選擇器

  4. 得到選擇器中的事件集合:Set<SelectionKey> key= selector.selectedKeys()

  5. Selectionkey:能夠經過它來判斷IO事件是否已經就緒

key. isAccptable:是否能夠接受客戶端的鏈接

key, isConnctionable:是否能夠鏈接服務端

key, isReadableo:緩衝區是否可讀

key, isWriteableo:緩衝區是否可寫

6.如何註冊

channel.regist(selector, Selectionkey.OP_WRITE)//註冊寫事件

channel.regist(Selector, Selectionkey.OP_READ);//註冊讀事件

channel.regist(Selector, Selectionkey.OP_CONNECT);//註冊鏈接事件

channel.regist(Selector, Selectionkey.OP_ACCEPT);//註冊請求事件

以上註冊成功以後就能夠經過SelectionKey來判斷io事件是否就緒,而後能夠進行後續操做。

來源連接 :

https://mp.weixin.qq.com/s/_zj9beaBmhD7xO6lk8avjA

相關文章
相關標籤/搜索