CUBは子供の白熊

Java SE 8 実践プログラミングの練習問題を解く

第6章 並行処理の機能強化 : 問題 3 : AtomicLong と LongAdder

問題

1,000個のスレッドを生成し、各スレッドは、ある一つのカウンターを100,000回インクリメントする
AtomicLong と LongAdder を使用した場合の性能を比較せよ

解答

■ AtomicLong

final int TASK = 1000;
final int COUNT = 100_000;

AtomicLong globalCounter = new AtomicLong(0);
CountDownLatch latch = new CountDownLatch(TASK);
ExecutorService pool = Executors.newCachedThreadPool();
long startTime = System.nanoTime();
for (int n = 0; n < TASK; n++) {
    pool.submit(
        () -> {
            for (int i = 0; i < COUNT; i++) {
                globalCounter.incrementAndGet();
            }
            latch.countDown();
        }
    );
}
pool.shutdown();
latch.await();
System.out.println("経過時間 : " + (System.nanoTime() - startTime)/1E9 + "秒");
System.out.println("カウンタ : " + globalCounter);

■ LongAdder

final int TASK = 1000;
final int COUNT = 100_000;

LongAdder globalCounter = new LongAdder();
CountDownLatch latch = new CountDownLatch(TASK);
ExecutorService pool = Executors.newCachedThreadPool();
long startTime = System.nanoTime();
for (int n = 0; n < TASK; n++) {
    pool.submit(
        () -> {
            for (int i = 0; i < COUNT; i++) {
                globalCounter.increment();
            }
            latch.countDown();
        }
    );
}
pool.shutdown();
latch.await();
System.out.println("経過時間 : " + (System.nanoTime() - startTime)/1E9 + "秒");
System.out.println("カウンタ : " + globalCounter);

所要時間は、私のマシン環境で
AtomicLong: 2.044秒
LongAdder : 0.610秒
となり、約4倍の差でした