1. 程式人生 > 實用技巧 >IO和NIO的總結

IO和NIO的總結

1、前置知識

同步和非同步

  • 同步:兩個同步任務相互依賴,並且一個任務必須以依賴於另一任務的某種方式執行。 比如在A->B事件模型中,你需要先完成 A 才能執行B。 再換句話說,同步呼叫中被呼叫者未處理完請求之前,呼叫不返回,呼叫者會一直等待結果的返回。
  • 非同步: 兩個非同步的任務完全獨立的,一方的執行不需要等待另外一方的執行。再換句話說,非同步呼叫種一呼叫就返回結果不需要等待結果返回,當結果返回的時候通過回撥函式或者其他方式拿著結果再做相關事情。

簡單來說:同步就是A來到B家裡借錢,A必須等到B把錢給A才能離開;而非同步就是A來到B家裡借錢,A可以先離開而不需要等待B返回結果,B可以去A那兒把錢送給A。

阻塞和非阻塞

  • 阻塞:阻塞就是發起一個請求,呼叫者一直等待請求結果返回,也就是當前執行緒會被掛起,無法從事其他任務,只有當條件就緒才能繼續。
  • 非阻塞:非阻塞就是發起一個請求,呼叫者不用一直等著結果返回,可以先去幹其他事情。

簡單來說:阻塞就是A和C同時想來到B家裡,但是A已經先進來了,因此C必須等待A離開才能進去;非阻塞就是A和C可以同時進去。

如何區分 “同步/非同步 ”和 “阻塞/非阻塞” 呢?

同步/非同步是從行為角度描述事物的,而阻塞和非阻塞描述的當前事物的狀態(等待呼叫結果時的狀態)。

2、 BIO (Blocking I/O)

同步阻塞I/O模式,資料的讀取寫入必須阻塞在一個執行緒內等待其完成。

採用BIO 通訊模型的服務端,通常由一個獨立的 Acceptor 執行緒負責監聽客戶端的連線。我們一般通過在while(true)迴圈中服務端會呼叫accept()方法等待接收客戶端的連線的方式監聽請求,請求一旦接收到一個連線請求,就可以建立通訊套接字在這個通訊套接字上進行讀寫操作,此時不能再接收其他客戶端連線請求,只能等待同當前連線的客戶端的操作執行完成。

不過可以通過多執行緒來支援多個客戶端的連線,n個客戶端就要有n個執行緒,也就是說它在接收到客戶端連線請求之後為每個客戶端建立一個新的執行緒進行鏈路處理,處理完成之後,通過輸出流返回應答給客戶端,執行緒銷燬。

在 Java 虛擬機器中,執行緒是寶貴的資源,執行緒的建立和銷燬成本很高,除此之外,執行緒的切換成本也是很高的。尤其在 Linux 這樣的作業系統中,執行緒本質上就是一個程序,建立和銷燬執行緒都是重量級的系統函式。如果併發訪問量增加會導致執行緒數急劇膨脹可能會導致執行緒堆疊溢位、建立新執行緒失敗等問題,最終導致程序宕機或者僵死,不能對外提供服務。

3、 NIO (New I/O)

NIO是一種同步非阻塞的I/O模型,在Java 1.4 中引入了 NIO 框架,對應 java.nio 包,提供了 Channel , Selector,Buffer等抽象。

NIO中的N可以理解為Non-blocking,不單純是New。它支援面向緩衝的,基於通道的I/O操作方法。 NIO提供了與傳統BIO模型中的SocketServerSocket相對應的SocketChannelServerSocketChannel兩種不同的套接字通道實現,兩種通道都支援阻塞和非阻塞兩種模式。阻塞模式使用就像傳統中的支援一樣,比較簡單,但是效能和可靠性都不好;非阻塞模式正好與之相反。對於低負載、低併發的應用程式,可以使用同步阻塞I/O來提升開發速率和更好的維護性;對於高負載、高併發的(網路)應用,應使用 NIO 的非阻塞模式來開發。

4、NIO的特性/NIO與IO區別

NIO BIO
是否阻塞 Java NIO使我們可以進行非阻塞IO操作。比如說,單執行緒中從通道讀取資料到buffer,同時可以繼續做別的事情,當資料讀取到buffer中後,執行緒再繼續處理資料。寫資料也是一樣的。另外,非阻塞寫也是如此。一個執行緒請求寫入一些資料到某通道,但不需要等待它完全寫入,這個執行緒同時可以去做別的事情。 Java IO的各種流是阻塞的。這意味著,當一個執行緒呼叫read()write()時,該執行緒被阻塞,直到有一些資料被讀取,或資料完全寫入。該執行緒在此期間不能再幹任何事情了

Buffer(緩衝區)

NIO 面向緩衝區(Buffer oriented)

Buffer是一個物件,它包含一些要寫入或者要讀出的資料。在NIO類庫中加入Buffer物件一個重要區別,NIO 是直接讀到 Buffer 中進行操作。

在NIO中,所有資料都是用緩衝區處理的。在讀取資料時,它是直接讀到緩衝區中的; 在寫入資料時,寫入到緩衝區中。任何時候訪問NIO中的資料,都是通過緩衝區進行操作。

最常用的緩衝區是 ByteBuffer,一個 ByteBuffer 提供了一組功能用於操作 byte 陣列。除了ByteBuffer,還有其他的一些緩衝區,事實上,每一種Java基本型別(除了Boolean型別)都對應有一種緩衝區。

BIO 面向流(Stream oriented)

在面向流的I/O中,可以將資料直接寫入或者將資料直接讀到 Stream 物件中。雖然 Stream 中也有 Buffer 開頭的擴充套件類,但只是流的包裝類,還是從流讀到緩衝區。

Channel (通道)

NIO 通過Channel(通道) 進行讀寫。通道是雙向的,可讀也可寫,而流的讀寫是單向的。無論讀寫,通道只能和Buffer互動。因為 Buffer,通道可以非同步地讀寫。

Selector (選擇器)

NIO有選擇器。

選擇器用於使用單個執行緒處理多個通道。因此,它需要較少的執行緒來處理這些通道。執行緒之間的切換對於作業系統來說是昂貴的。 因此,為了提高系統效率選擇器是有用的。

沒有