案例
- demo 類
- 起倆線程分别執行add、compare
- 乍一看,a、b“同時”自增,應該一直相等,compare中的判斷不會為true。
- 但是看日志:不僅有a<b成立,a>b有時也為 true。
- 評論裡肯定有人在這裡就笑了,這是你的代碼太垃圾,操作兩個字段a和b,有線程安全問題,應該為add方法加上鎖,確定a和b的++是原子性的,就不會錯了。
那麼,就在add方法加鎖看看?
public synchronized void add()
但,加鎖後問題并沒有解決。
1 為什麼鎖可以解決線程安全問題
因為隻有一個線程可拿到鎖,是以加鎖後的代碼中的資源操作線程安全。
但該案例中的 add 始終隻有一個線程在操作,顯然隻為 add 加鎖無意義。
是以因為兩個線程是交錯執行add和compare中的業務邏輯,而且這些業務邏輯不是原子性的:a++和b++操作中可以穿插在compare方法的比較代碼中;
a<b這種比較操作在位元組碼層面是三步,即不是原子的:
- 加載a
- 加載b
- 比較
應該為add和compare都加鎖,確定add執行時,compare無法讀取a和b:
public synchronized void add()
public synchronized void compare()
是以,使用鎖一定要梳理清楚線程、業務邏輯和鎖三者關系。