本系列譯自jakob jenkov的Java并發多線程教程,個人覺得很有收獲。由于個人水準有限,不對之處還望矯正!
盡管多線程有諸多的挑戰,但是多線程被廣泛使用的原因有以下幾點:
1、對資源的充分利用。
2、簡化程式設計
3、響應的及時性
假設一個應用程式從本地檔案系統中讀取并處理一個檔案,讓我們來假設從硬碟讀取檔案需要5秒,處理檔案需要兩秒,那麼處理兩個檔案則需要:
5秒 讀取A檔案
2秒 處理A檔案
5秒 讀取B檔案
2秒 處理B檔案
共需14秒
當從硬碟讀取檔案的時候,CPU大部分時間用在等待從硬碟讀取資料,CPU 在等待的這段時間是非常空閑的,是可以被利用來做其他事情的,通過改變執行順序,CPU 可以被更好的利用。看下面的執行順序:
5秒 讀取A檔案
5秒 讀取B檔案+2秒處理A檔案
共需12秒
到CPU等待A檔案讀取的時候,開始讀取B檔案,當B檔案正在讀取的時候,CPU 開始處理A檔案,記住,當CPU 等待從硬碟讀取檔案的時候,CPU 幾乎是空閑的。
通常,CPU 在等待IO操作時,可以做其他的事情的,不光是磁盤IO,網絡IO也是一樣的
如果你打算用一個單線程的程式去處理上面的問題,你不得不時刻跟蹤每個檔案的讀取和處理狀态。而用多線程,你隻需要啟動兩個線程,而每個線程隻需負責單個檔案讀取和處理。這些線程會被blocked當等待從磁盤上讀取檔案,在等待的同時,另外的線程可以利用CPU 來處理它已經讀到的資料,這樣做的結果就是,磁盤一直處于繁忙的狀态,不斷地從磁盤讀取資料到記憶體中。這樣做,對于磁盤和CPU 的使用率得到提升,同時對于程式來說也更簡單,因為每個線程隻需去跟蹤一個檔案的讀取和處理狀态
将單線程轉變為多線程的另一個目的是更具有響應的及時性。假設一個服務端程程式在一個端口上監聽請求,當收到請求後,它對這個請求進行相應的處理,然後再傳回去監聽另外的請求。服務端程式如下:
while(server is active){
listen for the request
process request
}
如果這個請求花費了很長的時間去處理,那麼用戶端就不能在此期間發送任何請求到服務端,隻有當服務端處理完目前請求再次回到監聽時才能接受新的請求。另一種設計是監聽線程把接受到的請求交給工作線程(work thread )然後立即傳回監聽。工作線程會對請求進行處理,并對用戶端傳回一個結果。這種設計模式如下:
listen for request
handle request to work thread
這種方式,監聽線程會很快繼續進行監聽,是以更多的用戶端可以發送更多的請求到服務端,服務端也變的更具響應性。這對桌面應用程式也是一樣的。