前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >原子操作组合与线程安全

原子操作组合与线程安全

作者头像
FunTester
发布2020-04-03 15:17:50
5210
发布2020-04-03 15:17:50
举报
文章被收录于专栏:FunTesterFunTester

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

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

下面是示例代码:

代码语言:javascript
复制
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,断言失败。

点击阅读原文,有兴趣的童鞋可以一起交流

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档