天天看點

BIO、NIO、AIO的差別和reactor模型

1.什麼是BIO,NIO,AIO

  • JAVA BIO:同步并阻塞,伺服器實作模式為一個連接配接一個線程,即用戶端有連接配接請求時伺服器端就需要啟動一個線程并處理,如果這個連接配接不做任何事情會造成不必要的開銷,當然可以通過線程池機制改善
  • JAVA NIO:同步非阻塞,伺服器實作模式為一個請求一個線程,即用戶端發送的連接配接請求都會注冊到多路複用器上,多路複用器輪詢到連接配接有IO請求時才啟動一個線程進行處理
  • JAVA AIO(NIO2):異步非阻塞,伺服器實作模式為一個有效請求一個線程,用戶端的I/O請求都是由OS先完成了再通知伺服器應用去啟動線程進行處理

2.使用場景

  • BIO方式适用于連接配接數目比較小且固定的架構,這種方式對伺服器資源要求比較高,并發局限于應用中,JDK1.4以前的唯一選擇,但程式直覺簡單易了解。
  • NIO方式适用于連接配接數目多且連接配接比較短(輕操作)的架構,比如聊天伺服器,并發局限于應用中,程式設計比較複雜,JDK1.4開始支援。
  • AIO方式使用于連接配接數目多且連接配接比較長(重操作)的架構,比如相冊伺服器,充分調用OS參與并發操作,程式設計比較複雜,JDK7開始支援。

3.BIO 同步并阻塞

tomcat采用的傳統的BIO(同步阻塞IO模型)+線程池模式,對于十萬甚至百萬連接配接的時候,傳統BIO模型是無能為力的:

①線程的建立和銷毀成本很高,在linux中,線程本質就是一個程序,建立銷毀都是重量級的系統函數

②線程本身占用較大的記憶體,像java的線程棧一般至少配置設定512K-1M的空間,如果系統線程過高,記憶體占用是個問題

③線程的切換成本高,作業系統發生線程切換的時候,需要保留線程的上下文,然後執行系統調用,如果線程數過高可能執行線程切換的時間甚至大于線程執行的時間,這時候帶來的表現是系統load偏高,CPUsy使用率很高

④容易造成鋸齒狀的系統負載。系統負載是用活動線程數或CPU核心數,一旦線程數量高但外部網絡環境不是很穩定,就很容易造成大量請求的結果同時傳回,激活大量阻塞線程進而使系統負載壓力過大。

4.NIO同步非阻塞

NIO基于Reactor,當socket有流可讀或可寫入socket,作業系統會相應的通知引用程式進行處理,應用再将流讀取到緩沖區或寫入作業系統。也就是,不是一個連結就要對應一個處理線程,而是一個有效請求對應一個線程,當連接配接沒有資料時,是沒有工作線程來處理的

Reactor模型

BIO、NIO、AIO的差別和reactor模型

nio隻有acceptor的服務線程是堵塞進行的,其他讀寫線程是通過注冊事件的方式,有讀寫事件激活時才調用線程資源區執行,不會一直堵塞等着讀寫操作,Reactor的瓶頸主要在于acceptor的執行,讀寫事件也是在這一塊分發

5.AIO異步非堵塞IO

BIO、NIO、AIO的差別和reactor模型

AIO需要一個連結注冊讀寫事件和回調方法,當進行讀寫操作時,隻須直接調用API的read或write方法即可,這兩種方法均為異步,對于讀操作而言,當有流可讀取時,作業系統會将可讀的流傳入read方法的緩沖區,并通知應用程式;對于寫操作而言,當作業系統将write方法傳遞的流寫入完畢時,作業系統主動通知應用程式

即,read/write方法都是異步的,完成後會主動調用回調函數

6.同步異步

  • 同步:發送一個請求,等待傳回,再發送下一個請求,同步可以避免出現死鎖,髒讀的發生
  • 異步:發送一個請求,不等待傳回,随時可以再發送下一個請求,可以提高效率,保證并發