1.阻塞和非阻塞java
阻塞和非阻塞是進程在訪問數據的時候,進程需不須要等待。linux
1. 阻塞api
當數據沒有準備好時,都會一直等待緩衝區中的數據準備就緒以後纔會開始處理,不然會一直等待下去。數組
2. 非阻塞安全
當進程訪問到數據緩衝區時,若是數據還未準備好,會直接返回不會一直等待,若是數據已經準備好了,也會直接返回。服務器
2.同步和異步網絡
同步和異步都是基於應用程序和操做系統處理IO事件鎖採用的方式。併發
同步:框架
同步是應用系統直接參與IO讀寫操做。在處理IO事件的時候必須阻塞在某個方法上面等待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也提供了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,也是抽象類。看看繼承結構。
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操做流程
服務端對象:ServerSocketChannel
客戶端對象:SocketChannel
選擇器:Selector selector= Selector.open();//這樣就打開了選擇器
得到選擇器中的事件集合:Set<SelectionKey> key= selector.selectedKeys()
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事件是否就緒,而後能夠進行後續操做。
來源連接 :