javaの同時プログラミングの1つのAtomicBoolean紹介を笑います。
7059 ワード
Javaのjava.util.co ncurrent.atomicというパッケージの下には多くの原子的操作のapiが提供されています。マルチスレッドで動作する原子性を保証できます。スレッドが安全でない操作は起こりません。により、ある時間帯に作業員が一人しかいない例を実現しました。スレッドのセキュリティコードは以下の通りです。 AtomicBoolean上記問題を解決するコード案:
public class BarWorker implements Runnable {
// ,
private static boolean exists = false;
private String name;
public BarWorker(String name) {
this.name = name;
}
@Override
public void run() {
if (!exists) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
exists = true;
System.out.println(name + " enter");
try {
System.out.println(name + " working");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + " leave");
exists = false;
} else {
System.out.println(name + " give up");
}
}
public static void main(String[] args) throws InterruptedException {
BarWorker bar1 = new BarWorker("bar1");
BarWorker bar2 = new BarWorker("bar2");
new Thread(bar1).start();
new Thread(bar2).start();
}
}
出力結果は以下の通りです。bar1 enter
bar2 enter
bar1 working
bar2 working
bar2 leave
bar1 leave
結論:同時に2人の従業員が作業に入ったのを見ることができます。これはexistsが判断と更新の間に原子的な操作ではないためです。途中でスレッドを使って1秒待ちました。第2労働者が入ってから、existsがまだfalseであることを発見しました。主な問題は判断と更新の間に他の仕事が発生しました。もちろん、判断と更新の間の待ち時間を取り除ければ、基本的に上記の問題は発生しません。しかし、完全に保証できません。この場合、同期synchronizedを採用します。でも本当にそうしなければなりませんか?実はそうではないです。聡明なjava大師たちは原子的操作のAtomicBooleanツールを提供してくれました。import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public class BarWorkerAuto implements Runnable {
// ,
private static AtomicBoolean exists = new AtomicBoolean(false);
private String name;
public BarWorkerAuto(String name) {
this.name = name;
}
@Override
public void run() {
if (exists.compareAndSet(false,true)) {
System.out.println(name + " enter");
try {
System.out.println(name + " working");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + " leave");
exists.set(false);
} else {
System.out.println(name + " give up");
}
}
public static void main(String[] args) throws InterruptedException {
BarWorkerAuto bar1 = new BarWorkerAuto("bar1");
BarWorkerAuto bar2 = new BarWorkerAuto("bar2");
new Thread(bar1).start();
new Thread(bar2).start();
}
}
出力結果は以下の通りです。bar1 enter
bar2 give up
bar1 working
bar1 leave
結論:同じ時間に一人の労働者だけが仕事に入ることが見られます。AtomicBooleanのcompreAndSetという方法は原子的な操作です。まず現在の値がexpectの値と同じかどうかを判断します。等しいなら、値をアップデートします。public final boolean compareAndSet(boolean expect, boolean update) {
int e = expect ? 1 : 0;
int u = update ? 1 : 0;
return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}