咱們知道io只是輸入輸出,在java語言中分爲同步阻塞的BIO、同步非阻塞的NIO、異步非阻塞的AIO,如今的IO,通常是用做兩種用途:一種是進行文件或者目錄的操做(將不一樣的輸入輸出源抽象成流,因此流本質就是從起源到接受的有序數據,即流就是數據),另外一種是進行套接字(Socket)操做(分爲ServerSocket——監聽其餘通信實體鏈接請求,是服務器端和Socket——鏈接到制定的服務器,是客戶端)。java
BIO是傳統的IO,又稱爲阻塞性IO編程
java中的BIO存在兩類,一共四個基類,分別是OutputStream/InputStream(字符流),Writer/Reader(字節流),後者兩類是爲了方便字節操做對前者進 行了封裝,底層仍是字符流(具體他們的區別,咱們在後續的博文中比較)。服務器
在進行文件或者目錄操做的時候,將數據的接收方抽象成水管,水管中的水滴就是最小的數據傳輸單元(對於字節流是一個字節,對於字符流是一個字 符),經過隱式的記錄指針來表示當前準備讀取水滴的位置,指針自動向後移動,數據接二連三發送,每一個基類中也有對應的方法對指針進行操縱,可是不能操 做讀取的方向,BIO數據的傳輸是單向的,也就是說,不能靈活的操做流中的數據發送的方向架構
在進行套接字操做的時候,accept()、connect()、write()、read()調用時會產生阻塞。一個請求一個線程,併發太高,線程壓力過大,會致使宕機,因此不能應對高併發,高訪問量的場景。併發
NIO(N能夠理解爲new,也能夠理解爲NonBlock)是新IO,非阻塞IO異步
NIO是面向通道(channel)的,面向緩衝區(buffer)的,通道至關於提供了運算環境,緩衝區是運輸數據的載體。socket
在進行文件或者目錄操做的時候,能夠經過通道或者緩衝區進行數據的讀寫(同一個channel中既能夠讀也能夠寫,是雙向的),全部對數據的操做都是通 過緩衝區操做的。函數
在進行套接字操做的時候,accept()、connect()、write()、read()調用時不會產生阻塞。一個有效請求對應給一個線程,鏈接沒有數據處理就沒有線程等待。因此能應對高併發,高訪問量的場景。高併發
AIO是異步IO,Netty在以前的版本中用過,可是如今不用了,如今這項技術尚未具體的行業版。性能
轉自其餘文章:
Java對BIO、NIO、AIO的支持:
Java BIO : 同步並阻塞,服務器實現模式爲一個鏈接一個線程,即客戶端有鏈接請求時服務器端就須要啓動一個線程進行處理,若是這個鏈接不作任何事情會形成沒必要要的線程開銷,固然能夠經過線程池機制改善。
Java NIO : 同步非阻塞,服務器實現模式爲一個請求一個線程,即客戶端發送的鏈接請求都會註冊到多路複用器上,多路複用器輪詢到鏈接有I/O請求時才啓動一個線程進行處理。
Java AIO(NIO.2) : 異步非阻塞,服務器實現模式爲一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啓動線程進行處理,
BIO、NIO、AIO適用場景分析:
BIO方式適用於鏈接數目比較小且固定的架構,這種方式對服務器資源要求比較高,併發侷限於應用中,JDK1.4之前的惟一選擇,但程序直觀簡單易理解。
NIO方式適用於鏈接數目多且鏈接比較短(輕操做)的架構,好比聊天服務器,併發侷限於應用中,編程比較複雜,JDK1.4開始支持。
AIO方式使用於鏈接數目多且鏈接比較長(重操做)的架構,好比相冊服務器,充分調用OS參與併發操做,編程比較複雜,JDK7開始支持。
另外,I/O屬於底層操做,須要操做系統支持,併發也須要操做系統的支持,因此性能方面不一樣操做系統差別會比較明顯。
在高性能的I/O設計中,有兩個比較著名的模式Reactor和Proactor模式,其中Reactor模式用於同步I/O,而Proactor運用於異步I/O操做。
在比較這兩個模式以前,咱們首先的搞明白幾個概念,什麼是阻塞和非阻塞,什麼是同步和異步,同步和異步是針對應用程序和內核的交互而言的,同步指的是用戶進程觸發IO操做並等待或者輪詢的去查看IO操做是否就緒,而異步是指用戶進程觸發IO操做之後便開始作本身的事情,而當IO操做已經完成的時候會獲得IO完成的通知。而阻塞和非阻塞是針對於進程在訪問數據的時候,根據IO操做的就緒狀態來採起的不一樣方式,說白了是一種讀取或者寫入操做函數的實現方式,阻塞方式下讀取或者寫入函數將一直等待,而非阻塞方式下,讀取或者寫入函數會當即返回一個狀態值。
通常來講I/O模型能夠分爲:同步阻塞,同步非阻塞,異步阻塞,異步非阻塞IO
同步阻塞IO:在此種方式下,用戶進程在發起一個IO操做之後,必須等待IO操做的完成,只有當真正完成了IO操做之後,用戶進程才能運行。JAVA傳統的IO模型屬於此種方式!
同步非阻塞IO:在此種方式下,用戶進程發起一個IO操做之後邊可返回作其它事情,可是用戶進程須要時不時的詢問IO操做是否就緒,這就要求用戶進程不停的去詢問,從而引入沒必要要的CPU資源浪費。其中目前JAVA的NIO就屬於同步非阻塞IO。
異步阻塞IO:此種方式下是指應用發起一個IO操做之後,不等待內核IO操做的完成,等內核完成IO操做之後會通知應用程序,這其實就是同步和異步最關鍵的區別,同步必須等待或者主動的去詢問IO是否完成,那麼爲何說是阻塞的呢?由於此時是經過select系統調用來完成的,而select函數自己的實現方式是阻塞的,而採用select函數有個好處就是它能夠同時監聽多個文件句柄,從而提升系統的併發性!
異步非阻塞IO:在此種模式下,用戶進程只須要發起一個IO操做而後當即返回,等IO操做真正的完成之後,應用程序會獲得IO操做完成的通知,此時用戶進程只須要對數據進行處理就行了,不須要進行實際的IO讀寫操做,由於真正的IO讀取或者寫入操做已經由內核完成了。目前Java中尚未支持此種IO模型。
注:
阻塞與非阻塞是指這個方法在執行的時候是否阻塞程序的繼續執行其餘與客戶端和服務器端無關程序。
附:BIO阻塞產生與放開的條件
* accept()會產生阻塞
* Listens for a connection to be made to this socket and accepts
* it. The method blocks until a connection is made.
* 當一個客戶端連入的時候,阻塞放開,若是沒有客戶端連入,就會產生阻塞
* read()會產生阻塞
* This method
* blocks until input data is available, the end of the stream is detected,
* or an exception is thrown.
* 當有數據可讀時,阻塞放開。
* write()也會產生阻塞,一直往出寫數據,可是沒有任何一方讀這個數據的時候
* 寫到必定量就會產生阻塞。(是寫到網卡的設備緩衝區裏)
* connect()一會產生阻塞, * Connects this socket to the server with a specified timeout value. * A timeout of zero is interpreted as an infinite timeout. The connection * will then block until established or an error occurs. * 直到成功連入服務端或拋異常,阻塞放開