盡管面臨很多挑戰多線程有一些優點使得它一直被使用這些優點是
● 資源利用率更好
● 程序設計在某些情況下更簡單
● 程序響應更快
資源利用率更好
想象一下一個應用程序需要從本地文件系統中讀取和處理文件的情景比方說從磁盤讀取一個文件需要秒處理一個文件需要秒處理兩個文件則需要
秒讀取文件A
秒處理文件A
秒讀取文件B
秒處理文件B
總共需要
秒
從磁盤中讀取文件的時候大部分的CPU時間用於等待磁盤去讀取數據在這段時間裡CPU非常的空閒它可以做一些別的事情通過改變操作的順序就能夠更好的使用CPU資源看下面的順序
秒讀取文件A
秒讀取文件B +
秒處理文件A
秒處理文件B
總共需要
秒
CPU等待第一個文件被讀取完然後開始讀取第二個文件當第二文件在被讀取的時候CPU會去處理第一個文件記住在等待磁盤讀取文件的時候CPU大部分時間是空閒的
總的說來CPU能夠在等待IO的時候做一些其他的事情這個不一定就是磁盤IO它也可以是網絡的IO或者用戶輸入通常情況下網絡和磁盤的IO比CPU和內存的IO慢的多
程序設計更簡單
在單線程應用程序中如果你想編寫程序手動處理上面所提到的讀取和處理的順序你必須記錄每個文件讀取和處理的狀態相反你可以啟動兩個線程每 個線程處理一個文件的讀取和操作線程會在等待磁盤讀取文件的過程中被阻塞在等待的時候其他的線程能夠使用CPU去處理已經讀取完的文件其結果就 是磁盤總是在繁忙地讀取不同的文件到內存中這會帶來磁盤和CPU利用率的提升而且每個線程只需要記錄一個文件因此這種方式也很容易編程實現
程序響應更快
將一個單線程應用程序變成多線程應用程序的另一個常見的目的是實現一個響應更快的應用程序設想一個服務器應用它在某一個端口監聽進來的請求當一個請求到來時它去處理這個請求然後再返回去監聽
服務器的流程如下所述
while(
server is active){
listen for request
process request
}
如果一個請求需要占用大量的時間來處理在這段時間內新的客戶端就無法發送請求給服務端只有服務器在監聽的時候請求才能被接收另一種設計是監聽線 程把請求傳遞給工作者線程(worker thread)然後立刻返回去監聽而工作者線程則能夠處理這個請求並發送一個回復給客戶端這種設計如下所述
while(server is active){
listen for request
hand request to worker thread
}
這種方式服務端線程迅速地返回去監聽因此更多的客戶端能夠發送請求給服務端這個服務也變得響應更快
桌面應用也是同樣如此如果你點擊一個按鈕開始運行一個耗時的任務這個線程既要執行任務又要更新窗口和按鈕那麼在任務執行的過程中這個應用程 序看起來好像沒有反應一樣相反任務可以傳遞給工作者線程(word thread)當工作者線程在繁忙地處理任務的時候窗口線程可以自由地響應其他用戶的請求當工作者線程完成任務的時候它發送信號給窗口線程窗口 線程便可以更新應用程序窗口並顯示任務的結果對用戶而言這種具有工作者線程設計的程序顯得響應速度更快
從一個單線程的應用到一個多線程的應用並不僅僅帶來好處它也會有一些代價不要僅僅為了使用多線程而使用多線程而應該明確在使用多線程時能多來的好處比所付出的代價大的時候才使用多線程如果存在疑問應該嘗試測量一下應用程序的性能和響應能力而不只是猜測
設計更復雜
雖然有一些多線程應用程序比單線程的應用程序要簡單但其他的一般都更復雜在多線程訪問共享數據的時候這部分代碼需要特別的注意線程之間的交互往往非常復雜不正確的線程同步產生的錯誤非常難以被發現並且重現以修復
上下文切換的開銷
當CPU從執行一個線程切換到執行另外一個線程的時候它需要先存儲當前線程的本地的數據程序指針等然後載入另一個線程的本地數據程序指針 等最後才開始執行這種切換稱為上下文切換(context switch)CPU會在一個上下文中執行一個線程然後切換到另外一個上下文中執行另外一個線程
上下文切換並不廉價如果沒有必要應該減少上下文切換的發生
增加資源消耗
線程在運行的時候需要從計算機裡面得到一些資源除了CPU線程還需要一些內存來維持它本地的堆棧它也需要占用操作系統中一些資源來管理線程 我們可以嘗試編寫一個程序讓它創建個線程這些線程什麼事情都不做只是在等待然後看看這個程序在運行的時候占用了多少內存
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27296.html