zoukankan      html  css  js  c++  java
  • LongAccumulator类的BUG——reset方法并不能保证初始值正确赋值

    LongAccumulator.reset方法并不能重置重置LongAccumulator的identity:初始值正确,使其恢复原来的初始值。当初始值为0是不会发生这个问题,而当我们设置初始值如1时,就会导致后续的计算操作增加了5份初始值,目前猜测原因是因为代码中LongAccumulator在并发量比较大的情况下,操作数据的时候,相当于把这个数字分成了很多份数字 ,而初始化的时候也是初始化了多份数据,导致初始值叠加了多份。不知道这是个bug么?待解惑。

    在此记录下来希望有遇到这种情况的同学注意。解决方法便是要么初始值identity=0不会有这种问题;或者有需要使用reset方法重置的改为重新创建个LongAccumulator处理。

    源码:

    public void reset() {
        Cell[] as = cells; Cell a;
        base = identity;
        if (as != null) {
            for (int i = 0; i < as.length; ++i) {
                if ((a = as[i]) != null)
                    //对多个cell进行初始值赋值导致后面计算叠加了多份初始值
                    a.value = identity;
            }
        }
    }
    

    示例:

    public class LongAccumulatorTest {
        //设置初始值为1查看输出结果
        private static volatile LongAccumulator count = new LongAccumulator((x, y) -> x + y, 1);
    
        public static void main(String[] args) throws InterruptedException {
            for (int i = 0; i < 5; i++) {
                count.reset();
                averageTest();
            }
        }
    
        public static void averageTest() throws InterruptedException {
            long t1 = System.currentTimeMillis();
            //自定义包含策略
            ThreadPoolExecutor executor = new ThreadPoolExecutor(50, 50, 60,
                    TimeUnit.SECONDS, new LinkedBlockingQueue<>(5),
                    new DemoThreadFactory("订单创建组"), new ThreadPoolExecutor.AbortPolicy());
            CountDownLatch latch = new CountDownLatch(50);
            for (int i = 0; i < 50; i++) {
                executor.execute(() -> {
                    try {
                        for (int j = 0; j < 1000000; j++) {
                            count.accumulate(1);
                        }
                    } finally {
                        latch.countDown();
                    }
    
                });
            }
            latch.await();
            long t2 = System.currentTimeMillis();
            System.out.println(String.format("结果:%s,耗时(ms):%s", count.longValue(), (t2 - t1)));
            executor.shutdown();
        }
    }
    

    输出:这时候你会发现只有第一次计算是正确的,只要使用了rest方法重置就会导致这个错误。

    结果:50000001,耗时(ms):185
    结果:50000005,耗时(ms):143
    结果:50000005,耗时(ms):139
    结果:50000005,耗时(ms):162
    结果:50000005,耗时(ms):142
  • 相关阅读:
    Trie Tree和Radix Tree
    DataNode Layout升级解决Du操作引发的性能问题
    Write-Ahead Log(WAL)的工作原理
    YARN的共享存储服务
    AWS S3存储基于Hadoop之上的一致性保证
    简单聊聊HDFS RBF第二阶段工作近期的一些进展
    基于 Confluence 6 数据中心的 SAML 单点登录设置你的身份提供者
    基于 Confluence 6 数据中心的 SAML 单点登录设置 SSL/TLS
    Confluence 6 基于 Confluence 数据中心的 SAML 单点登录
    Confluence 6 用自带的用户管理
  • 原文地址:https://www.cnblogs.com/castamere/p/13650793.html
Copyright © 2011-2022 走看看