1. 程式人生 > >《java併發程式設計的藝術》第一章--上下文切換、避免死鎖、資源限制的挑戰

《java併發程式設計的藝術》第一章--上下文切換、避免死鎖、資源限制的挑戰

主要是學習的簡單記錄,用來加深印象。第一章主要還是理論多,作者簡單的描述。

1.1.1上下文切換

也就是CPU切換排程執行緒。不管是單核還是多核,CPU會給每個執行緒分配CPU時間片,時間片是CPU分配給執行緒的時間,因為時間片非常短,所以CPU通過不停地切換執行緒執行,讓我們感覺多個執行緒是同時執行,時間片一般是幾十毫秒(ms)。當一個執行緒執行完一個時間片後CPU會切換到其他執行緒,此時前一個執行緒會暫停,儲存對應的任務狀態,等再次切回來的時候會載入這個任務的狀態繼續執行,而不是重新執行。從儲存到再載入的過程就是一次上下文的切換。

1.1.2如何減少上下文切換

並不是執行緒越多程式執行就越快,執行緒多的話導致上下文切換也頻繁,那麼需要考慮減少上下文切換。減少上下文切換的方法有無鎖併發程式設計、CAS演算法、使用最少執行緒和使用協程。

  • 無鎖併發程式設計。多執行緒競爭鎖時,會引起上下文切換,所以多執行緒處理資料時,可以用一
  • 些辦法來避免使用鎖,如將資料的ID按照Hash演算法取模分段,不同的執行緒處理不同段的資料。
  • CAS演算法。Java的Atomic包使用CAS演算法來更新資料,而不需要加鎖。
  • 使用最少執行緒。避免建立不需要的執行緒,比如任務很少,但是建立了很多執行緒來處理,這
  • 樣會造成大量執行緒都處於等待狀態。
  • 協程:在單執行緒裡實現多工的排程,並在單執行緒裡維持多個任務間的切換。

1.2 如何避免死鎖

避免死鎖的幾個常見方法。

  • 避免一個執行緒同時獲取多個鎖。
  • 避免一個執行緒在鎖內同時佔用多個資源,儘量保證每個鎖只佔用一個資源。
  • 嘗試使用定時鎖,使用lock.tryLock(timeout)來替代使用內部鎖機制。
  • 對於資料庫鎖,加鎖和解鎖必須在一個數據庫連線裡,否則會出現解鎖失敗的情況。

1.3資源的限制

(1)什麼是資源限制

資源限制是指在進行併發程式設計時,程式的執行速度受限於計算機硬體資源或軟體資源。

例如,伺服器的頻寬只有2Mb/s,某個資源的下載速度是1Mb/s每秒,系統啟動10個執行緒下載資

源,下載速度不會變成10Mb/s,所以在進行併發程式設計時,要考慮這些資源的限制。硬體資源限

制有頻寬的上傳/下載速度、硬碟讀寫速度和CPU的處理速度。軟體資源限制有資料庫的連線

數和socket連線數等。

(2)資源限制引發的問題

在併發程式設計中,將程式碼執行速度加快的原則是將程式碼中序列執行的部分變成併發執行,

但是如果將某段序列的程式碼併發執行,因為受限於資源,仍然在序列執行,這時候程式不僅不

會加快執行,反而會更慢,因為增加了上下文切換和資源排程的時間。例如,之前看到一段程

序使用多執行緒在辦公網併發地下載和處理資料時,導致CPU利用率達到100%,幾個小時都不

能執行完成任務,後來修改成單執行緒,一個小時就執行完成了。

(3)如何解決資源限制的問題

對於硬體資源限制,可以考慮使用叢集並行執行程式。既然單機的資源有限制,那麼就讓

程式在多機上執行。比如使用ODPS、Hadoop或者自己搭建伺服器叢集,不同的機器處理不同

的資料。可以通過“資料ID%機器數”,計算得到一個機器編號,然後由對應編號的機器處理這

筆資料。

對於軟體資源限制,可以考慮使用資源池將資源複用。比如使用連線池將資料庫和Socket

連線複用,或者在呼叫對方webservice介面獲取資料時,只建立一個連線。

(4)在資源限制情況下進行併發程式設計

如何在資源限制的情況下,讓程式執行得更快呢?方法就是,根據不同的資源限制調整

程式的併發度,比如下載檔案程式依賴於兩個資源——頻寬和硬碟讀寫速度。有資料庫操作

時,涉及資料庫連線數,如果SQL語句執行非常快,而執行緒的數量比資料庫連線數大很多,則

某些執行緒會被阻塞,等待資料庫連線。

1.4 總結

本章介紹了在進行併發程式設計時,大家可能會遇到的幾個挑戰,並給出了一些解決建議。有

的併發程式寫得不嚴謹,在併發下如果出現問題,定位起來會比較耗時和棘手。所以,對於

Java開發工程師而言,筆者強烈建議多使用JDK併發包提供的併發容器和工具類來解決併發

問題,因為這些類都已經通過了充分的測試和優化,均可解決了本章提到的幾個挑戰。