线程安全map_原子操作组合与线程安全

除了操作原子性之外,还有一个比较容易引起线程不安全的原因:安全方法组合。使用多个线程安全的方法组合成一个方法,也有可能导致线程不安全的情况出现。

以ConcurrentHashMap类为例,ConcurrentHashMap是一个高并发高性能的map实现类,他的每个方法都是线程安全的。

下面是示例代码:

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() );
	}	
}

下面是控制台打印信息:

89c9ff95acca269ef31b3b3f521c5301.png

至于为什么会这样的,原因是因为在代理第5行执行完之后,在下面复制的判断过程中依然存在着多个线程同时进去if-else判断的可能性,借助vmlens这个插件,能够很明显看到原因,图如下:

242d359afcc956be427e646603dcc6ff.png

图中可以看到在执行ConcurrentHashMap的原子操作get和put方法时候,出现了线程间的竞争,13和14线程分别先获取到了对象的锁,然后取得了map.get(1)的值,此时值为null,两个线程的取值都是null,剩下的就比较明了了。两个线程都进入了if-else判断的第一个条件语句中,又先后复制map.put(1,1),这样最终的结果map.get(1).intValue()就等于1,断言失败。

readme.markdown · 八音弦/tester - 码云 Gitee.com​gitee.com
d7358c80b451184c7148f78b49504ab3.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值