天天看點

第1章 并發程式設計的挑戰

第1章 并發程式設計的挑戰

1.1 上下文切換

即使是單核處理器也支援多線程執行代碼,CPU通過給每個線程配置設定CPU時間片來實作這個機制。

  • CPU時間片:CPU配置設定給各個線程的時間,時間片非常短,是以我們感受不到CPU在不斷切換線程執行。時間片一般是幾十毫秒
  • 上下文切換:CPU在執行完目前任務的時間片後,會先儲存這個任務的狀态,然後才切換到下一個任務。其實就是任務從儲存到再加載的過程,切換的代價就是影響多線程的執行速度

并發程式設計的效率就比串行執行高?

從圖中我們可以看出達到百萬級别以上的并發量,并發執行才有性能上的優勢。主要是因為線程有建立和上下文切換的開銷

減少上下文切換的措施

  • 無鎖并發程式設計:多線程競争鎖時,會引起上下文切換,鎖不存在就可以避免這種情況,可以将資料的id按照雜湊演算法取模分段,不同的線程處理不同段多的資料。
  • CAS算法:Java的Atomic包使用CAS算法來更新資料,不需要加鎖,也就避免了上述情況。
  • 隻使用必要的線程:任務很少但線程很多會造成大量線程處于等待狀态
  • 協程:在單線程裡實作多任務的排程,并在單線程裡維持多個任務間的切換,這裡使得線程之間的切換變成了線程内任務之間的切換

1.2 死鎖

鎖的應用場景很多,使資料變得相對安全,但鎖也有一些問題,包括死鎖。一旦出現死鎖,就會造成系統功能不可用。

  • 死鎖,簡單地說就是兩個線程互相持有對方需要的資源,雙方都在等待對方釋放鎖,陷入了僵持。

死鎖的場景很多,如線程拿到了鎖,但在釋放鎖之前抛出了異常導緻無法釋放鎖,也有因為陷入了死循環而持續占有鎖。

避免死鎖的方法

  • 避免一個線程同時擷取多個鎖,鎖之間的關系相對簡單較好
  • 避免一個線程在鎖内同時占有多個資源
  • 嘗試使用定時鎖,使用lock.tryLock(timeout)來代替内部鎖機制
  • 對于資料庫鎖,加鎖和解鎖必須在一個資料庫連接配接裡,否則會出現解鎖失敗的情況

資源限制

軟硬體資源的限制,如伺服器帶寬隻有2Mb/s,資源的下載下傳速度為1Mb/s,開十個線程不會變成10Mb/s。硬體資源限制有帶寬的上傳/下載下傳速度、硬碟讀寫速度和CPU的處理速度。軟體資源限制有資料庫的連接配接數,socket連接配接數等

資源限制引發的問題

如果并發執行的代碼,因為受限于資源,依然在串行執行,效果甚至會不如直接串行執行,因為多了上下文切換和資源排程的時間

解決資源限制的問題

對于硬體資源限制,可以使用ODPS、Hadoop或其他伺服器叢集,使用雜湊演算法取模分段,然後不同的機器處理不同段的資料。

繼續閱讀