本文是對NIO知識的概括與整理java
1)阻塞(Block)和非租塞(NonBlock):git
阻塞和非阻塞是進程在訪問數據的時候,數據是否準備就緒的一種處理方式,當數據沒有準備的時候阻塞:每每須要等待縗衝區中的數據準備好事後才處理其餘的事情,否則一直等待在那裏。數據庫
非阻塞:當咱們的進程訪問咱們的數據緩衝區的時候,若是數據沒有準備好則直接返回,不會等待。若是數據已經準備好,也直接返回數組
2)同步(Synchronization)和異步(Async)的方式:緩存
同步和異步都是基於應用程序私操做系統處理IO事件所採用的方式,好比同步:是應用程序要直接參與IO讀寫的操做。異步:全部的IO讀寫交給搡做系統去處理,應用程序只須要等待通知。服務器
同步方式在處理IO事件的時候,必須阻塞在某個方法上靣等待咱們的IO事件完成(阻塞IO事件或者經過輪詢IO事件的方式).對於異步來講,全部的IO讀寫都交給了搡做系統。這個時候,咱們能夠去作其餘的事情,並不拓要去完成真正的IO搡做,當搡做完成IO後.會給咱們的應用程序一個通知多線程
同步:阻塞到IO事件,阻塞到read成則write。這個時候咱們就徹底不能作本身的事情,讓讀寫方法加入到線程裏面,而後阻塞線程來實現,對線程的性能開銷比較大,併發
block IO與Non-block IOapp
1)區別異步
IO模型IONIO
方式從硬盤到內存從內存到硬盤
通訊面向流(鄉村公路)面向緩存(高速公路,多路複用技術)
處理阻塞IO(多線程)非阻塞IO(反應堆Reactor)
觸發無選擇器(輪詢機制)
2)面向流與面向緩衝
Java NIO和IO之間第一個最大的區別是,IO是面向流的.NIO是面向緩衝區的。Java IO面向流意味着毎次從流中讀一個成多個字節,直至讀取全部字節,它們沒有被緩存在任何地方,此外,它不能先後移動流中的數據。若是須要先後移動從流中讀取的教據,須要先將它緩存到一個緩衝區。Java NIO的緩衝導向方法略有不一樣。數據讀取到一個它稍後處理的緩衝區,霱要時可在緩衝區中先後移動。這就增長了處理過程當中的靈活性。可是,還須要檢查是否該緩衝區中包含全部您須要處理的數裾。並且,需確保當更多的數據讀入緩衝區時,不要覆蓋緩衝區裏還沒有處理的數據。
3)阻塞與非阻塞
Java IO的各類流是阻塞的。這意味着,當一個線程調用read() 或 write()時,該線程被阻塞,直到有一些數據被讀取,或數據徹底寫入。該線程在此期間不能再幹任何事情了。 Java NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,可是它僅能獲得目前可用的數據,若是目前沒有數據可用時,就什麼都不會獲取。而不是保持線程阻塞,因此直至數據變的能夠讀取以前,該線程能夠繼續作其餘的事情。 非阻塞寫也是如此。一個線程請求寫入一些數據到某通道,但不須要等待它徹底寫入,這個線程同時能夠去作別的事情。 線程一般將非阻塞IO的空閒時間用於在其它通道上執行IO操做,因此一個單獨的線程如今能夠管理多個輸入和輸出通道(channel)。
4)選擇器(Selector)
Java NIO的選擇器容許一個單獨的線程來監視多個輸入通道,你能夠註冊多個通道使用一個選擇器,而後使用一個單獨的線程來「選擇"通道:這些通裏已經有能夠處理的褕入,或者選擇已準備寫入的通道。這選懌機制,使得一個單獨的線程很容易來管理多個通道。
5)NIO和BIO讀取文件
BIO讀取文件
BIO從一個阻塞的流中一行一行的讀取數據
NIO讀取文件
通道是數據的載體,buffer是存儲數據的地方,線程每次從buffer檢查數據通知給通道
6)處理數據的線程數
NIO:一個線程管理多個鏈接
BIO:一個線程管理一個鏈接
在Java1.4以前的I/O系統中,提供的都是面向流的I/O系統,系統一次一個字節地處理數據,一個輸入流產生一個字節的數據,一個輸出流消費一個字節的數據,面向流的I/O速度很是慢,而在Java 1.4中推出了NIO,這是一個面向塊的I/O系統,系統以塊的方式處理處理,每個操做在一步中產生或者消費一個數據庫,按塊處理要比按字節處理數據快的多。
在NIO中有幾個核心對象須要掌握:緩衝區(Buffer)、通道(Channel)、選擇器(Selector)。
緩衝區其實是一個容器對象,更直接的說,其實就是一個數組,在NIO庫中,全部數據都是用緩衝區處理的。在讀取數據時,它是直接讀到緩衝區中的; 在寫入數據時,它也是寫入到緩衝區中的;任什麼時候候訪問 NIO 中的數據,都是將它放到緩衝區中。而在面向流I/O系統中,全部數據都是直接寫入或者直接將數據讀取到Stream對象中。
在NIO中,全部的緩衝區類型都繼承於抽象類Buffer,最經常使用的就是ByteBuffer,對於Java中的基本類型,基本都有一個具體Buffer類型與之相對應,它們之間的繼承關係以下圖所示:
1)其中的四個屬性的含義分別以下:
容量(Capacity):緩衝區可以容納的數據元素的最大數量。這一個容量在緩衝區建立時被設定,而且永遠不能改變。
上界(Limit):緩衝區的第一個不能被讀或寫的元素。或者說,緩衝區中現存元素的計數。
位置(Position):下一個要被讀或寫的元素的索引。位置會自動由相應的 get( )和 put( )函數更新。
標記(Mark):下一個要被讀或寫的元素的索引。位置會自動由相應的 get( )和 put( )函數更新。
2)Buffer的常見方法以下所示:
flip(): 寫模式轉換成讀模式
rewind():將 position 重置爲 0 ,通常用於重複讀。
clear() :
compact(): 將未讀取的數據拷貝到 buffer 的頭部位。
mark(): reset():mark 能夠標記一個位置, reset 能夠重置到該位置。
Buffer 常見類型: ByteBuffer 、 MappedByteBuffer 、 CharBuffer 、 DoubleBuffer 、 FloatBuffer 、 IntBuffer 、 LongBuffer 、 ShortBuffer 。
3)基本操做
Buffer基礎操做: 連接
緩衝區分片,緩衝區分配,直接緩存區,緩存區映射,緩存區只讀:連接
4)緩衝區存取數據流程
存數據時position會++,當中止數據讀取的時候
調用flip(),此時limit=position,position=0
讀取數據時position++,一直讀取到limit
clear() 清空 buffer ,準備再次被寫入 (position 變成 0 , limit 變成 capacity) 。
通道是一個對象,經過它能夠讀取和寫入數據,固然了全部數據都經過Buffer對象來處理。咱們永遠不會將字節直接寫入通道中,相反是將數據寫入包含一個或者多個字節的緩衝區。一樣不會直接從通道中讀取字節,而是將數據從通道讀入緩衝區,再從緩衝區獲取這個字節。
在NIO中,提供了多種通道對象,而全部的通道對象都實現了Channel接口。它們之間的繼承關係以下圖所示:
1)使用NIO讀取數據
在前面咱們說過,任什麼時候候讀取數據,都不是直接從通道讀取,而是從通道讀取到緩衝區。因此使用NIO讀取數據能夠分爲下面三個步驟:
從FileInputStream獲取Channel
建立Buffer
將數據從Channel讀取到Buffer中
2)使用NIO寫入數據
使用NIO寫入數據與讀取數據的過程相似,一樣數據不是直接寫入通道,而是寫入緩衝區,能夠分爲下面三個步驟:
從FileInputStream獲取Channel
建立Buffer
將數據從Channel寫入到Buffer中
1)阻塞IO模型
在老的IO包中,serverSocket和socket都是阻塞式的,所以一旦有大規模的併發行爲,而每個訪問都會開啓一個新線程。這時會有大規模的線程上下文切換操做(由於都在等待,因此資源全都被已有的線程吃掉了),這時不管是等待的線程仍是正在處理的線程,響應率都會降低,而且會影響新的線程。
2)NIO
Java NIO是在jdk1.4開始使用的,它既能夠說成「新IO」,也能夠說成非阻塞式I/O。下面是java NIO的工做原理:
1.由一個專門的線程來處理全部的IO事件,並負責分發。
2.事件驅動機制:事件到的時候觸發,而不是同步的去監視事件。
3.線程通信:線程之間經過wait,notify等方式通信。保證每次上下文切換都是有意義的。減小無謂的線程切換。
注:每一個線程的處理流程大概都是讀取數據,解碼,計算處理,編碼,發送響應。
傳統的 server / client 模式會基於 TPR ( Thread per Request ) .服務器會爲每一個客戶端請求創建一個線程.由該線程單獨負貴處理一個客戶請求。這種模式帶未的一個問題就是線程數是的劇增.大量的線程會增大服務器的開銷,大多數的實現爲了不這個問題,都採用了線程池模型,並設置線程池線程的最大數量,這又帶來了新的問題,若是線程池中有 200 個線程,而有 200 個用戶都在進行大文件下載,會致使第 201 個用戶的請求沒法及時處理,即使第 201 個用戶只想請求一個幾 KB 大小的頁面。傳統的 Sorvor / Client 模式以下圍所示:
NIO 中非阻塞IO採用了基於Reactor模式的工做方式,IO調用不會被阻塞,相反是註冊感興趣的特色IO事件,如可讀數據到達,新的套接字等等,在發生持定率件時,系統再通知咱們。 NlO中實現非阻塞IO的核心設計Selector,Selector就是註冊各類IO事件的地方,並且當那些事件發生時,就是這個對象告訴咱們所發生的事件。
當有讀或者寫等任何註冊的事件發生時,能夠從Selector中得到相應的SelectionKey,同時從SelectionKey中能夠找到發生的事件和該事件所發生的具體的SelectableChannel,以得到客戶端發送過來的數據。
使用NIO中非阻塞IO編寫服務器處理程序,有三個步驟
1.向Selector對象註冊感興趣的事件
2.從Selector中獲取感興趣的事件
3.根據不一樣事件進行相應的處理
Selector是NIO的核心
epool模型
1)Selector
Selector的open
2)ServerSocketChannel
ServerSocketChannel.open
Asynchronous IO
異步非阻塞IO
BIO ServerSocket
NIO ServerSocketChannel
AIO AsynchronousServerSocketChannel
AIO通訊
看完本文的同窗都掌握了嗎,還沒掌握的同窗能夠收藏喲,也能夠轉給其餘須要的同窗。