1. 程式人生 > >阻塞式和多執行緒 BIO 詳解 ServerSocket例項

阻塞式和多執行緒 BIO 詳解 ServerSocket例項

1.什麼是IO

流是一種抽象概念,它代表了資料的無結構化傳遞。按照流的方式進行輸入輸出,資料被當成無結構的位元組或字元序列。從流中取得資料的操作稱為讀取,而向流中新增資料的操作稱為寫入。用來進行輸入輸出操作的流就稱為IO流。換句話說,IO流就是以流的方式進行輸入輸出。

用通俗的話講,I就是in =進來=輸入流,O就是out=出去=輸出流,這裡的輸入輸出是以記憶體為參考物件,即輸入流可以理解為位元組從硬碟內跑到記憶體裡了,  硬碟-->記憶體 ,輸出流是位元組從記憶體跑到硬碟中 , 記憶體-->硬碟以記憶體為參考物件,記憶體出去就是輸出流,要寫資料,進來記憶體就是輸入流,要讀資料。IO是計算機作業系統對資源讀和寫的操作,可以簡單理解為對資源的複製拷貝,只不過是目的地有所區別而已。初學者對IO可能會有點懵,輸入輸出到底是誰從哪裡輸入到哪裡,又輸出到哪裡,下面參考一張圖更加容易理解。

2.阻塞 非阻塞  同步  非同步

阻塞和非阻塞相對於資料而言

 阻塞:在讀取或者寫入資料的時候,一直需要等待作業系統(核心)準備資料,若資料已經就緒,IO開始進行讀或寫,否則,就處於阻塞等待狀態,等待資料的就緒,期間不能做其他事情,程式無法向下執行。

非阻塞:不論作業系統的資料是否已經準備好,程式都能繼續往下執行,不需等待資料的就緒。

同步和非同步是相對於IO事件而言,側重的方式不一樣

同步:在IO事件發生的時候,程式只能等待IO事件處理完畢,方可繼續往下執行

非同步:不關心IO事件是否處理完畢,讓作業系統去執行該事件的同時,繼續往下執行,等待該事件操作完畢時的一個通知,在往下執行的某個時候,會收到作業系統完成該事件的通知。  

3.阻塞式IO  一般稱為BIO -- BlockedIO


使用jdk提供的ServerSocket  Socket套接字可以模擬服務端與客戶端之間的通訊,或者基於此API,封裝伺服器和客戶端。在IO事件發生時,是處於阻塞狀態的。下面看程式碼

服務端程式碼


客戶端程式碼


執行結果:先執行服務端,再執行客戶端(執行main方法);




4.多執行緒式IO

由於阻塞式IO有阻塞,且每次只能為一個客戶端服務,多個客戶端連線需要依次等待,效率很低,資源利用也少。

如果使用多執行緒,每次客戶端連線之後,將任務放在新的執行緒去執行,那麼多個客戶端的任務執行互不干擾,可以併發的去執行。可以很大程式上解決單執行緒BIO的問題,這種BIO為多執行緒BIO

。但是也有缺點,併發量太大,執行緒和任務比為:n:n,即一個任務需要開啟一個執行緒處理。指數級的會消耗大量的執行緒,執行緒的開啟和執行是非常消耗資源的,對CPU的負擔也非常大

所以可以採用執行緒池的思想去解決,但是執行緒池在一定程式上限制了執行緒的數量,也會造成在海量併發情況下的等待阻塞,這種方式稱為偽非同步IO。

多執行緒IO 客戶端程式碼不變,服務端程式碼稍微改造一下即可。

new Thread().start(); 傳入執行的執行緒體,new Runable()實現run()方法


客戶端複製一下TcpClient類 

執行結果:

5.非阻塞 NIO 

非阻塞式NIO  程式在發生IO事件時不會發生阻塞。此篇文章不再詳解,將另開篇幅介紹。