2つのスレッドで読み取り/書き込みを行い、ロックを取得するオーバーヘッド(または潜在的なデッドロックリスク)を望まない場合は、volatile
インスタンス変数をときどき使用します。たとえば、いくつかのクラスでゲッターとして公開されるint IDを定期的に更新するタイマースレッド:
public class MyClass {
private volatile int id;
public MyClass() {
ScheduledExecutorService execService = Executors.newScheduledThreadPool(1);
execService.scheduleAtFixedRate(new Runnable() {
public void run() {
++id;
}
}, 0L, 30L, TimeUnit.SECONDS);
}
public int getId() {
return id;
}
}
私の質問:JLSは32ビットの読み取りがアトミックであることを保証するだけであることを考えると、揮発性のlongを使用してeverにポイントがありますか? (つまり、64ビット)。
警告:volatile
よりもsynchronized
を使用することが最適化前のケースであると言って返信しないでください。 synchronized
をいつどのように使用するかはよく知っていますが、volatile
が望ましい場合もあります。たとえば、Springコンテキストがメインスレッドで各Beanのプロパティを初期化する保証がないため、シングルスレッドアプリケーションで使用するSpring Beanを定義するときは、volatile
インスタンス変数を使用する傾向があります。
これは例で示すことができます
コード
public class VolatileTest {
private long foo;
private volatile long bar;
private static final long A = 0xffffffffffffffffl;
private static final long B = 0;
private int clock;
public VolatileTest() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
foo = clock % 2 == 0 ? A : B;
bar = clock % 2 == 0 ? A : B;
clock++;
}
}
}).start();
while (true) {
long fooRead = foo;
if (fooRead != A && fooRead != B) {
System.err.println("foo incomplete write " + Long.toHexString(fooRead));
}
long barRead = bar;
if (barRead != A && barRead != B) {
System.err.println("bar incomplete write " + Long.toHexString(barRead));
}
}
}
public static void main(String[] args) {
new VolatileTest();
}
}
出力
foo incomplete write ffffffff00000000
foo incomplete write ffffffff00000000
foo incomplete write ffffffff
foo incomplete write ffffffff00000000
これは、32ビットVM、64ビットで実行しているときにのみ発生しますVM数分で単一のエラーを取得できませんでした。
「揮発性」には複数の目的があります。
while (l != 0) {}
と考えてください)。もっとありますか?