Java ロックなしの同期処理を実装するAtomicクラス

Atomicクラス

java.util.concurrent.atomicパッケージでは、値の代入/参照処理をハードウェアレベルで原子的(Atomic)に実行する手段を提供します。

  • AtomicBoolean
  • AtomicInteger
  • AtomicIntegerArray
  • AtomicLong
  • AtomicLongArray

これらのクラスを利用することで、synchronized修飾子やReentrantLockクラスのようにロックを使用する必要なく、処理を同期できます。
各クラスで使用できる処理には、次のようなものがあります。

Atomicクラスの主なメソッド

メソッド 概要 AtomicBoolean
使用可否
get() 現在値を取得 O
getAndSet(newValue) 現在の値を取得し、指定された値を設定 O
set(newValue) 指定された値を設定 O
getAndAdd(delta) 指定された値を追加(操作前の値を取得) X
addAndGet(delta) 指定された値を追加(操作後の値を取得) X
getAndDecrement() 現在の値を1減少(操作前の値を取得) X
decrementAndGet() 現在の値を1減少(操作後の値を取得) X
getAndIncrement() 現在の値を1インクリメント(操作前の値を取得) X
incrementAndGet() 現在の値を1インクリメント(操作後の値を取得) X

使用例

次は、synchronized修飾子を使用した例(incrementメソッド)をAtomicIntegerクラスで書き直したものです。標準の「i++」演算は原子的ではありませんが、AtomicInteger#getAndIncrementメソッドは原子的であるため、値の取得から増分、再代入までの過程に他のthreadが割り込みません。

AtomicSample.java

package com.devkuma.basic.atomic;

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicSample {
    private AtomicInteger count = new AtomicInteger();

    public static void main(String[] args) {
        AtomicSample as = new AtomicSample();
        as.execute();
    }

    public void execute() {
        final int THREAD_MAX = 300000;
        Thread[] ts = new Thread[THREAD_MAX];
        for (int i = 0; i < THREAD_MAX; i++) {
            ts[i] = new Thread(new MyThread(this));
            ts[i].start();
        }
        for (int i = 0; i < THREAD_MAX; i++) {
            try {
                ts[i].join();
            } catch (InterruptedException e) {
                System.out.println(e);
            }
        }
        System.out.println(count);
    }

    public void increment() {
        count.getAndIncrement();
    }

    private static class MyThread implements Runnable {
        private AtomicSample _counter;

        public MyThread(AtomicSample counter) {
            this._counter = counter;
        }

        @Override
        public void run() {
            _counter.increment();
        }
    }
}

実行結果:

300000