原子性:乙個或多個操作在cpu執行的過程中不被中斷的特性原子性問題的源頭是執行緒切換,作業系統做執行緒切換依賴於cpu中斷,所以禁止cpu中斷就能禁止執行緒切換。
示例:在32位cpu上執行long型別變數的寫操作,long型別變數是64位,所以會被拆分為兩次寫操作(寫高32位和寫低32位)
1.單核cpu場景下,同一時刻只有乙個執行緒在執行,禁止cpu中斷,意味著作業系統不會重新排程執行緒,也就是禁止了執行緒切換,獲得cpu使用權的執行緒就可以不間斷執行,所以兩次寫操作,要麼都被執行,要麼都沒有被執行,具備原子性。
2.多核cpu場景下,同一時刻有可能有兩個執行緒在同時執行,乙個執行緒執行在cpu-1上,乙個執行緒執行在cpu-2上,此時禁止cpu中斷,只能保證cpu上的執行緒連續執行,不能保證同一時刻只有乙個執行緒在執行,如果兩個執行緒同時寫long型別變數的高32位,就會出現bug。
互斥:同一時刻只有乙個執行緒在執行。若能保證對共享變數的修改是互斥的,無論是單核cpu或者多核cpu,都能夠保證原子性。
鎖模型synchronized
class x
// 修飾靜態方法
synchronized static void bar()
// 修飾**塊
object obj = new object();
void baz()
}}
當修飾靜態方法的時候,鎖定的是當前類的class物件;
當修飾非靜態方法的時候,鎖定的是當前例項物件this;
class x
// 修飾靜態方法
synchronized(x.class) static void bar()
}
細粒度鎖:用不同的鎖對受保護的資源進行精細化管理,能夠提公升效能。
轉賬**
class account } }
怎麼保證轉賬操作沒有併發問題?
誤區:直接加synchronized
class account } }
問題原因:this這把鎖只能保護自己的餘額this.balance,保護不了別人的餘額target.balance
正確方案:用account.class 作為共享的鎖
class account }}
}
缺點:用account.class作為鎖,則所有的轉賬操作穿行化了。 互斥鎖,解決原子性問題以及加鎖後引發的死鎖
互斥鎖,解決原子性問題以及加鎖後引發的死鎖 原子性的問題就是執行緒切換。在單核時代,同一時刻只有乙個執行緒工作,禁用cpu中斷就能禁止執行緒切換。多核時代,同一時刻可能有多個執行緒在執行,禁用cpu中斷並不能解決原子性問題。經過上述分析得出結論,同一時刻只有乙個執行緒執行是解決原子性問題的必要條件,...
Golang 原子操作與互斥鎖
先來看乙個 package main import fmt runtime sync var counter int32 wg sync.waitgroup func main func addcounter whoami string final counter is 2 首先這個程式是起了兩個 ...
C 互斥量 原子鎖 自旋鎖等比較
現象 1 單執行緒無鎖速度最快,但應用場合受限 2 多執行緒無鎖速度第二快,但結果不對,未保護臨界 段 3 多執行緒原子鎖第三快,且結果正確 4 多執行緒互斥量較慢,慢與原子鎖近10倍,結果正確 5 多執行緒自旋鎖最慢,慢與原子鎖30倍,結果正確。結論 原子鎖速度最快,互斥量和自旋鎖都用保護多執行緒...