Java ロックなしの同期処理を実装するAtomicクラス
Atomicクラス
java.util.concurrent.atomicパッケージでは、値の代入/参照処理をハードウェアレベルで原子的(Atomic)に実行する手段を提供します。
AtomicBooleanAtomicIntegerAtomicIntegerArrayAtomicLongAtomicLongArray
これらのクラスを利用することで、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