- BIO(blocking io,同步阻塞)
場景:客戶端向服務端發送請求,服務端會為每個客戶端建立一個線程來響應,問題來了,如果客戶端出現了延時等異常,服務端為客戶端建立的線程,就會一直出於等待狀態,這個線程就會占用很長時間(因為數據的准備和處理都在這個線程上完成),更糟糕的是,如果有大量並發訪問,服務器就會建立大量線程響應,引起服務器資源枯竭。
BIO的網絡編程模型基本是C/S模型,即兩個進程間的通信。
服務端提供IP和監聽端口,客戶端通過連接操作向服務端監聽的地址發起連接請求,通過三次握手連接,如果連接成功,雙方就可以通過套接字進行通信。
傳統的同步阻塞模型開發中,serverSocket負責綁定ip地址,啟動監聽端口;socket負責發起連接操作,連接成功后,雙方通過輸入流和輸出流進行同步阻塞式通信。
BIO的通信模型:
采用BIO通信模型的服務端,通常由一個獨立的acceptor線程負責監聽客戶端的連接,它收到客戶端連接請求后為每個客戶端創建一個新的線程進行鏈路處理,處理完成后,通過輸出流返回應答給客戶端,線程銷毀。即典型的一請求一應答通信模型。
通信模型圖:
偽異步I/0編程
可以通過線程池管理。
BIO的缺點:
在讀取數據較慢(數據量大、網絡傳輸慢等),大量並發情況下,其他接入的消息,只能一直等待,這就是最大的弊端。
- NIO(not-blocking io,同步非阻塞)
JDK1.4中引入java.io.nio.*包中引入新的java i/o庫,目的是提高速度。實際上,舊的i/o已經使用nio重新實現過,即使我們不顯式的使用nio編程,也能從中受益。速度的提高在文件i/o和網絡i/o中都可能發生,我們只討論后者。
Nio最重要的一個地方是當一個連接創建后,不需要對應一個線程,這個連接會被注冊到多路復用器上面,所以所有的連接只需要一個線程就可以搞定,當這個線程中的多路復用器進行輪詢的時候,發現連接上有請求的話,才開啟一個線程進行處理,就是一個請求一個線程模式。
在nio的處理方式中,當一個請求過來時,開啟線程進行處理,可能會等待后端應用的資源,其實這個線程就被阻塞了,當並發上來的時候,也會有bio一樣的問題。
模型圖:
- AIO(Asynchronous io,異步非阻塞)
與nio不同的是,當進行讀寫操作時,只需調用api的read或write方法即可。這兩種方法都是異步的。
讀
當有流可讀取時,操作系統會將可讀的流傳入read方法的緩沖區,並通知應用程序。
寫
當操作系統將write方法傳遞的流寫入完畢時,操作系統主動通知應用程序。
可以理解為,read/write方法都是異步的,完成后會主動調用回調函數。
- 三者區別
BIO:同步並阻塞,服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當然可以通過線程池機制改善。
NIO:同步非阻塞,服務器實現模式為一個請求一個線程,即客戶端發送的連接請求都會注冊到多路復用器上,多路復用器輪詢到連接有I/O請求時才啟動一個線程進行處理。
AIO:異步非阻塞,服務器實現模式為一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啟動線程進行處理。
- 三者適用場景
BIO:適用於連接數目比較小且固定的架構,這種方式對服務器資源要求比較高,並發局限於應用中,JDK1.4以前的唯一選擇,但程序直觀簡單易理解。
NIO:適用於連接數目多且連接比較短(輕操作)的架構,比如聊天服務器,並發局限於應用中,編程比較復雜,JDK1.4開始支持。
AIO:適用於連接數目多且連接比較長(重操作)的架構,比如相冊服務器,充分調用OS參與並發操作,編程比較復雜,JDK7開始支持。