原子操作組合與執行緒安全
阿新 • • 發佈:2019-08-13
public class TestTwoAtomicMethods { private final ConcurrentHashMap<Integer,Integer> map = new ConcurrentHashMap<Integer,Integer>(); @Interleave public void update() { Integer result = map.get(1); if( result == null ) { map.put(1, 1); } else { map.put(1, result + 1 ); } } @Test public void testUpdate() throws InterruptedException { Thread first = new Thread( () -> { update(); } ); Thread second = new Thread( () -> { update(); } ); first.start(); second.start(); first.join(); second.join(); } @After public void checkResult() { assertEquals( 2 , map.get(1).intValue() ); } }
下面是控制檯列印資訊: 至於為什麼會這樣的,原因是因為在代理第5行執行完之後,在下面複製的判斷過程中依然存在著多個執行緒同時進去if-else判斷的可能性,藉助vmlens這個外掛,能夠很明顯看到原因,圖如下:
圖中可以看到在執行ConcurrentHashMap的原子操作get和put方法時候,出現了執行緒間的競爭,13和14執行緒分別先獲取到了物件的鎖,然後取得了map.get(1)的值,此時值為null,兩個執行緒的取值都是null,剩下的就比較明瞭了。兩個執行緒都進入了if-else判斷的第一個條件語句中,又先後複製map.put(1,1),這樣最終的結果map.get(1).intValue()就等於1,斷言失敗。