深刻理解BIO、NIO、AIO以及應用場景

補充概念:

同步與異步面試

  • 同步: 同步就是發起一個調用後,被調用者未處理完請求以前,調用不返回。redis

  • 異步: 異步就是發起一個調用後,馬上獲得被調用者的迴應表示已接收到請求,可是被調用者並無返回結果,此時咱們能夠處理其餘的請求,被調用者一般依靠事件,回調等機制來通知調用者其返回結果。

同步和異步的區別最大在於異步的話調用者不須要等待處理結果,被調用者會經過回調等機制來通知調用者其返回結果。編程

阻塞和非阻塞數組

  • 阻塞: 阻塞就是發起一個請求,調用者一直等待請求結果返回,也就是當前線程會被掛起,沒法從事其餘任務,只有當條件就緒才能繼續。服務器

  • 非阻塞: 非阻塞就是發起一個請求,調用者不用一直等着結果返回,能夠先去幹其餘事情。

概念:

1.BIO (Blocking I/O):

同步並阻塞,服務器的實現模式是一個鏈接一個線程,這樣的模式很明顯的一個缺陷是:因爲客戶端鏈接數與服務器線程數成正比關係,可能形成沒必要要的線程開銷,嚴重的還將致使服務器內存溢出。固然,這種狀況能夠經過線程池機制改善,但並不能從本質上消除這個弊端。markdown

2.NIO(New I/O):

在JDK1.4之前,Java的IO模型一直是BIO,但從JDK1.4開始,JDK引入的新的IO模型NIO,它是同步非阻塞的。而服務器的實現模式是多個請求一個線程,即請求會註冊到多路複用器Selector上,多路複用器輪詢到鏈接有IO請求時才啓動一個線程處理。網絡

2.1 NIO的特性/NIO與IO區別架構

1)Non-blocking IO(非阻塞IO)併發

IO流是阻塞的,NIO流是不阻塞的。異步

Java NIO使咱們能夠進行非阻塞IO操做。好比說,單線程中從通道讀取數據到buffer,同時能夠繼續作別的事情,當數據讀取到buffer中後,線程再繼續處理數據。寫數據也是同樣的。另外,非阻塞寫也是如此。一個線程請求寫入一些數據到某通道,但不須要等待它徹底寫入,這個線程同時能夠去作別的事情。

Java IO的各類流是阻塞的。這意味着,當一個線程調用 read() 或 write() 時,該線程被阻塞,直到有一些數據被讀取,或數據徹底寫入。該線程在此期間不能再幹任何事情了

2)Buffer(緩衝區)

IO 面向流(Stream oriented),而 NIO 面向緩衝區(Buffer oriented)。

Buffer是一個對象,它包含一些要寫入或者要讀出的數據。在NIO類庫中加入Buffer對象,體現了新庫與原I/O的一個重要區別。在面向流的I/O中·能夠將數據直接寫入或者將數據直接讀到 Stream 對象中。雖然 Stream 中也有 Buffer 開頭的擴展類,但只是流的包裝類,仍是從流讀到緩衝區,而 NIO 倒是直接讀到 Buffer 中進行操做。

在NIO厙中,全部數據都是用緩衝區處理的。在讀取數據時,它是直接讀到緩衝區中的; 在寫入數據時,寫入到緩衝區中。任什麼時候候訪問NIO中的數據,都是經過緩衝區進行操做。

最經常使用的緩衝區是 ByteBuffer,一個 ByteBuffer 提供了一組功能用於操做 byte 數組。除了ByteBuffer,還有其餘的一些緩衝區,事實上,每一種Java基本類型(除了Boolean類型)都對應有一種緩衝區。

3)Channel (通道)

NIO 經過Channel(通道) 進行讀寫。

通道是雙向的,可讀也可寫,而流的讀寫是單向的。不管讀寫,通道只能和Buffer交互。由於 Buffer,通道能夠異步地讀寫。

4)Selectors(選擇器)

NIO有選擇器,而IO沒有。

選擇器用於使用單個線程處理多個通道。所以,它須要較少的線程來處理這些通道。線程之間的切換對於操做系統來講是昂貴的。所以,爲了提升系統效率選擇器是有用的。

2.3 NIO 讀數據和寫數據方式

一般來講NIO中的全部IO都是從 Channel(通道) 開始的。

  • 從通道進行數據讀取 :建立一個緩衝區,而後請求通道讀取數據。

  • 從通道進行數據寫入 :建立一個緩衝區,填充數據,並要求通道寫入數據。

數據讀取和寫入操做圖示:

2.4 NIO核心組件簡單介紹

NIO 包含下面幾個核心的組件:

  • Channel(通道)

  • Buffer(緩衝區)

  • Selector(選擇器)

3.AIO(Asynchronous I/O):

JDK1.7發佈了NIO2.0,這就是真正意義上的異步非阻塞,服務器的實現模式爲多個有效請求一個線程,客戶端的IO請求都是由OS先完成再通知服務器應用去啓動線程處理(回調)。

適用場景:

BIO方式適用於鏈接數目比較小且固定的架構,這種方式對服務器資源要求比較高,併發侷限於應用中,JDK1.4之前的惟一選擇,但程序直觀簡單易理解。

NIO方式適用於鏈接數目多且鏈接比較短(輕操做)的架構,好比聊天服務器,併發侷限於應用中,編程比較複雜,JDK1.4開始支持。

AIO方式使用於鏈接數目多且鏈接比較長(重操做)的架構,好比相冊服務器,充分調用OS參與併發操做,編程比較複雜,JDK7開始支持。

總結:

NIO容許你用一個單獨的線程或幾個線程管理不少個channels(網絡的或者文件的),代價是程序的處理和處理IO相比更加複雜

若是你須要同時管理成千上萬的鏈接,可是每一個鏈接只發送少許數據,例如一個聊天服務器,用NIO實現會更好一些,類似的,若是你須要保持不少個到其餘電腦的鏈接,例如P2P網絡,用一個單獨的線程來管理全部出口鏈接是比較合適的

若是你只有少許的鏈接可是每一個鏈接都佔有很高的帶寬,同時發送不少數據,傳統的IO會更適合

推薦閱讀:

  • 進程同步的五種機制以及優缺點(翻譯)

  • redis五種數據類型的實現方式,經常使用命令,應用場景

  • redis和memcahed的共同點,區別以及應用場景

  • Overload和Override的區別

  • 詳解TCP的三次握手與四次揮手及面試題(很全面)
相關文章
相關標籤/搜索