今日はJavaでAtomicInteger
を見ていきます。アトミック操作は、他の操作からの干渉なしに単一のタスク単位で実行されます。マルチスレッド環境ではデータの不整合を避けるために、アトミック操作が必要です。
AtomicInteger
共有の
count
変数を4回増やす単純なマルチスレッドプログラムを作成しましょう。したがって、2つのスレッドがある場合、count
の値は8になるはずです。JavaAtomic.java
package com.journaldev.concurrency;
public class JavaAtomic {
public static void main(String[] args) throws InterruptedException {
ProcessingThread pt = new ProcessingThread();
Thread t1 = new Thread(pt, "t1");
t1.start();
Thread t2 = new Thread(pt, "t2");
t2.start();
t1.join();
t2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ProcessingThread implements Runnable {
private int count;
@Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count++;
}
}
public int getCount() {
return this.count;
}
private void processSomething(int i) {
// いくつかのジョブを処理する
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
上記のプログラムを実行すると、count
の値が5、6、7、8の間で変動することに気付くでしょう。その理由は、count++がアトミック操作ではないためです。したがって、1つのスレッドが値を読み取り、1を増やすときに、他のスレッドが古い値を読み取って誤った結果につながります。この問題を解決するには、countの増分操作がアトミックであることを確認する必要があります。これは同期を使用して行うことができますが、Java 5のjava.util.concurrent.atomic
は同期を使用せずにこのアトミック操作を実現するためのintとlongのラッパークラスを提供しています。
Java AtomicIntegerの例
現在の値を1つ増やす`AtomicInteger`メソッド`incrementAndGet()`が、常にカウント値を8として出力するようになったプログラムを以下に示します。
package com.journaldev.concurrency;
import java.util.concurrent.atomic.AtomicInteger;
public class JavaAtomic {
public static void main(String[] args) throws InterruptedException {
ProcessingThread pt = new ProcessingThread();
Thread t1 = new Thread(pt, "t1");
t1.start();
Thread t2 = new Thread(pt, "t2");
t2.start();
t1.join();
t2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ProcessingThread implements Runnable {
private AtomicInteger count = new AtomicInteger();
@Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count.incrementAndGet();
}
}
public int getCount() {
return this.count.get();
}
private void processSomething(int i) {
// いくつかのジョブを処理
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
アトミック操作のために並行クラスを使用する利点は、同期の心配が不要であることです。これによりコードの読みやすさが向上し、エラーの可能性が減少します。また、アトミック操作の並行クラスは、リソースのロックを含む同期よりも効率的であると想定されています。
Source:
https://www.digitalocean.com/community/tutorials/atomicinteger-java