原子操做組合與線程安全

除了操做原子性以外,還有一個比較容易引發線程不安全的緣由:安全方法組合。使用多個線程安全的方法組合成一個方法,也有可能致使線程不安全的狀況出現。 以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

相關文章
相關標籤/搜索