1. 程式人生 > 實用技巧 >LongAccumulator類的BUG——reset方法並不能保證初始值正確賦值

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