除了操做原子性以外,還有一個比較容易引發線程不安全的緣由:安全方法組合。使用多個線程安全的方法組合成一個方法,也有可能致使線程不安全的狀況出現。 以ConcurrentHashMap類爲例,ConcurrentHashMap是一個高併發高性能的map實現類,他的每一個方法都是線程安全的。 下面是示例代碼:git
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這個插件,可以很明顯看到緣由,圖以下: api
圖中能夠看到在執行ConcurrentHashMap的原子操做get和put方法時候,出現了線程間的競爭,13和14線程分別先獲取到了對象的鎖,而後取得了map.get(1)的值,此時值爲null,兩個線程的取值都是null,剩下的就比較明瞭了。兩個線程都進入了if-else判斷的第一個條件語句中,又前後複製map.put(1,1),這樣最終的結果map.get(1).intValue()就等於1,斷言失敗。安全
歡迎有興趣的童鞋一塊兒交流markdown