03.01 如何理解BIO、NIO、AIO?

孫見福


先需要了解幾個概念:同步和異步,阻塞和非阻塞。

同步和異步

  • 同步:進程觸發IO操作的時候,必須親自處理;你必須親自去銀行取錢。

  • 異步:進程觸發IO操作的時候,可以不親自處理,它把操作委託給OS處理,委託的時候需要告知數據的地址和大小,然後自己去做別的事情,當IO操作結束後會得到通知;你把銀行卡給我,讓我幫你去銀行取錢,你需要告訴我銀行卡密碼和取多少錢,我取完了之後把錢給你。

總結:自己幹就是同步,別人幹就是異步。

阻塞和非阻塞

  • 阻塞:進程觸發IO操作的時候,如果此時此時沒辦法讀或者寫,那麼進程就一直等待,直到讀寫結束;比如你去銀行ATM取錢,前面有人在排隊,那麼就要一直等待,直到你取完錢;

  • 非阻塞:進程觸發IO操作的時候,如果此時此時沒辦法讀或者寫,那麼就先去做別的,等到有通知後,再繼續讀寫;比如你去銀行櫃檯取錢,人比較多,那就先領一個號,等著叫到號再去對應的窗口辦理業務;這裡不太恰當的是,我們等待的過程中,還得聽著叫號。

總結:我要等著不能做其他事就是阻塞,我不用等可以做其他事就是異步。

BIO、NIO、AIO

  • BIO:同步阻塞;一個請求過來,應用程序開了一個線程,等IO準備好,讀寫IO也是自己幹;但是為一個請求就啟動一個線程,開銷是比較大的,因為啟動和銷燬線程開銷很大,每個線程都要佔用內存,所以可以引入線程池,可以在一定程度上減少這些開銷;

  • NIO:同步非阻塞;不用等待IO準備,準備好了會通知,不過IO操作還是要自己幹;NIO是一種多路複用機制,利用單線程輪詢事件,Channel來決定做什麼,避免連接數多的時候,頻繁進行線程切換導致性能問題(Select階段阻塞)。

  • AIO:異步非阻塞;因為事情不是自己做,其實也沒有阻塞一說(都是非阻塞);AIO是在NIO的基礎上,引入異步通道的概念;NIO是採用輪詢的方式,不停地詢問stream中數據是否準備好了,準備好了就處理;AIO是向操作系統註冊IO監聽,操作系統完成IO操作了之後,主動通知,觸發響應的函數。

我將持續分享Java開發、架構設計、程序員職業發展等方面的見解,希望能得到你的關注。


會點代碼的大叔


這裡先回答你下BIO和NIO是什麼。

首先需要明白阻塞 非阻塞 同步 異步的概念,這裡引用下史蒂文斯的《UNIX網絡編程》中的幾張圖。



阻塞IO

圖中可以看到阻塞IO,一直阻塞在recvfrom方法調用上,直接數據複製完成



非阻塞IO

圖中可以看到非阻塞IO調用的recvfrom方法如果無數據直接返回,應用進程可以不斷輪詢是否有數據



IO複用

圖中可以看到IO複用,進程不再去輪詢獲取數據了,而是有select去查看數據是否準備好,準備好了,你再調用recvfrom方法去讀取數據



異步IO

異步IO,你發起系統調用,連數據都不用自己去讀取,而是操作系統直接給你複製到用戶空間,再回調你。

所以說同步和異步是針對用戶空間和內核空間交互而言的,而阻塞和非阻塞是針對用戶進程訪問數據而言的。強烈推薦下《UNIX網絡編程》。

BIO

java中的BIO是同步阻塞的。先看下服務端的例子



ServerSocket

這裡實例下ServerSocket的使用方法,可以看出一個連接過來就需要創建一個線程來處理連接,這裡可以使用線程池進行優化。

NIO



NIO的使用和注意的地方我都寫圖裡了。

NIO就是同步非阻塞,連接請求都會註冊到多路複用器上,多路複用器輪詢到連接有I/O請求時才進行處理,還是需要用戶自己去讀取數據,所以是同步的,但是不用阻塞在IO線程上,所以是非阻塞的。

學習NIO,還需要學習下 Buffer、Channel的使用。

Buffer

Buffer 可以理解為一個數組,可以進行數據的讀寫。在使用NIO的時候,我們的數據必須通過buffer和Channel進行交互。

Buffer 三個重要屬性:position、limit、capacity。

capacity:它代表這個緩衝區的容量,一旦設定就不可以更改。

position :初始值是 0,每寫入一個值,position 就自動加 1。讀也是類似的,每讀一個值,position 就自動加 1。寫操作切換讀操作的時候,可以調用flip,position 會歸零,這樣就可以從頭開始讀寫了。

limit:初始狀態下,limit 代表的是最大能寫入的數據,這個時候 limit 等於 capacity。調用flip後limit 等於 Buffer 中實際的數據大小,可以小於capacity。

Channel

Channel 通道,用於進行讀寫操作。一般使用channel.read(buffer) 和 channel.write(buffer)來讀寫數據。和流類似,但流是單向的,Channel是雙向的。

希望對你有所幫助,有幫助記得點贊哦!可以關注下,後面持續分享架構和Java的文章,謝謝!


淺析架構


BIO是一個連接一個線程。

NIO是一個請求一個線程。

AIO是一個有效請求一個線程。


分享到:


相關文章: