上下文切換
單核處理器是如何支持多線程編程的? CPU通過給每個線程分配CPU時間片來實現(xiàn)。
- 時間片是CPU分配給各個線程的時間,時間片非常短,CPU通過不停切換線程執(zhí)行,切換時間很快,讓人感覺是在同時執(zhí)行。
- CPU通過時間片算法來循環(huán)執(zhí)行任務,當前任務執(zhí)行完一個時間片后會切換到下一個任務,切換前輝保存上一個任務的狀態(tài),便于下次切回的時候可以再加載這個任務的狀態(tài)。任務從保存到再加載的過程就是一次上下文切換。
- 因為線程有創(chuàng)建和上下文的切換的開銷,并發(fā)執(zhí)行累加操作次數(shù)沒有很高的時候,速度會比串行執(zhí)行慢。
測試上下文切換次數(shù)和時長的工具
- 使用Lmbench3可以測量上下文切換的時長
- 使用vmstat可以測量上下文切換的次數(shù)
如何減少上下文切換
- 無鎖并發(fā)編程。多線程競爭鎖時,會引起上下文切換,可以用些方法來避免用鎖。比如對數(shù)據(jù)id計算取模分段,不同線程處理不同段的數(shù)據(jù)。
- CAS算法。CAS:Compare and Swap, 翻譯成比較并交換。
java.util.concurrent包中借助CAS實現(xiàn)了區(qū)別于synchronouse同步鎖的一種樂觀鎖。 - 使用最少線程。避免創(chuàng)建不需要的線程。比如任務很少,不比創(chuàng)建大量線程,可能會導致大量線程處于等待狀態(tài)。
- 協(xié)程:在單線程里實現(xiàn)多任務的調(diào)度,并在單線程里維持多個任務間的切換。具體java如何實現(xiàn)協(xié)程要找個時間研究下。
死鎖
dump分析死鎖
- 一旦出現(xiàn)死鎖,業(yè)務是可感知的,不能繼續(xù)提供服務。只能通過dump線程查看是哪個線程出現(xiàn)了問題。
- Jstack是JDK自帶的命令行工具,主要用于線程Dump分析
-
我們先用Jps來查看java進程id(或者Linux的ps命令)
image.png -
jstack的使用
image -
jstack輸出線程dump信息到文件
image -
查看文件,關鍵字是at DeadThread.run,比如at DeadThread.run(DeadThread.java:37),說明Thread-1實在DeadThread類的37行處發(fā)生死鎖
image.png
避免死鎖的常見方法
- 避免一個線程同時獲取多個鎖。
- 避免一個線程在鎖內(nèi)同時占用多個資源,盡量保證每個鎖只占用一個資源。
- 嘗試使用定時鎖,使用
lock.tryLock(timeout)來替代使用內(nèi)部鎖機制。 - 對于數(shù)據(jù)庫鎖,加鎖和解鎖必須在一個數(shù)據(jù)庫連接里,否則會出現(xiàn)解鎖失效的情況。



