web-dev-qa-db-ja.com

Javaスレッドセーフ?

揮発性int in Java thread-safe?つまり、ロックなしで安全に読み書きできますか?

52
shawn

はい、あなたはそれから読み込み、それを安全に書き込むことができます-しかし、それは読み込み/変更/書き込みサイクルであるため、安全にインクリメントするなどの複合的なことはできません。また、other変数へのアクセスと相互作用する方法の問題もあります。

Volatileの正確な性質は率直に混乱しています(詳細については、JLSの メモリモデルのセクションを参照してください )-私はpersonally通常、 AtomicInteger を代わりに使用します。

65
Jon Skeet

[...]ロックなしで安全に読み書きできるように?

はい、読み取りは常に最後の書き込みの値になります(読み取りと書き込みは両方ともアトミック操作です)。

揮発性の読み取り/書き込みは、実行時にいわゆる発生前関係を導入します。

Java言語仕様 第17章:スレッドとロック

揮発性フィールド(8.3.1.4)への書き込みは、そのフィールドの以降の読み取りの前に発生します。

言い換えると、揮発性変数を処理する場合、スレッドが変数に書き込まれた最新の値を取得することを保証するために、synchronizedキーワードを使用して明示的に同期(発生前の関係を導入)する必要はありません。

Jon Skeetが指摘しているように、volatile変数の使用は制限されており、一般的にJava.util.concurrent代わりにパッケージ。

6
aioobe

Javaはスレッドセーフになります。アクセスと言うときは、volatile_var = 10またはint temp = volatile_var(基本的に定数値での書き込み/読み取りなど) )。Javaの揮発性キーワードにより、2つのことが保証されます。

  1. 読むときは、常にメインメモリの値を取得します。一般的に、JVMは最適化のためにレジスタを使用するか、より一般的な用語でローカルメモリ変数の保存/アクセスに使用します。そのため、マルチスレッド環境では、各スレッドが変数の異なるコピーを見る場合があります。ただし、揮発性にすることで、変数への書き込みがメインメモリにフラッシュされ、読み取りもメインメモリから行われるため、スレッドが変数の正しいコピーを確認できるようになります。
  2. Volatileへのアクセスは自動的に同期されます。したがって、JVMは変数の読み取り/書き込み中に順序を保証します。

ただし、Jon Skeetは、非アトミック操作(volatile_var = volatile + 1)では、異なるスレッドが予期しない結果を得る可能性があることを正しく述べています。

2
Saurabh

1)2つのスレッドが共有変数を読み書きしている場合、そのためにvolatileキーワードを使用するだけでは十分ではありません。その場合は、変数の読み取りと書き込みがアトミックであることを保証するために、同期を使用する必要があります。 volatile変数の読み取りまたは書き込みは、スレッドの読み取りまたは書き込みをブロックしません。これを実現するには、クリティカルセクションの周りにsynchronizedキーワードを使用する必要があります。

2)同期ブロックの代替として、Java.util.concurrentパッケージにある多くのアトミックデータ型の1つを使用することもできます。たとえば、AtomicLong、AtomicReference、または他のいずれか。

1つのライタースレッドと複数のリーダースレッドがある場合、スレッドセーフです。

class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}

注:ヘルパーが不変である場合、volatileキーワードは必要ありません。シングルトンは適切に動作します。

複数のスレッドによってインクリメントされているカウンターの場合(読み取り書き込み操作)は、正しい答えを与えません。この状態は、競合状態でも示されます。

public class Counter{
private volatile int i;
public int increment(){
i++;
}
}

注:ここではvolatileは役に立ちません。

0
Rahul Saxena

Volatileが他のvolatile変数に依存していない場合、そのスレッドは読み取り操作に対して安全です。揮発性の書き込みの場合、スレッドの安全性は保証されません。

揮発性の変数iがあり、その値がjなどの別の揮発性変数に依存しているとします。スレッド1は変数jにアクセスしてインクリメントし、CPUキャッシュからメインメモリ内で変数を更新しようとしています。 Thread-2が
Thread-1の前の変数iは、メインメモリのjを実際に更新できます。 iの値は、正しくないjの古い値ごとになります。ダーティリードとも呼ばれます。

0
Ajay Verma

常にではない。

複数のスレッドが変数を読み書きしている場合、スレッドセーフではありません。 1つのライタースレッドと複数のリーダースレッドがある場合、スレッドセーフです。

スレッドを安全に探しているなら、 AtomicXXX クラスを使用してください

単一変数のロックフリースレッドセーフプログラミングをサポートするクラスの小さなツールキット。

本質的に、このパッケージのクラスは、揮発性の値、フィールド、および配列要素の概念を、フォームのアトミックな条件付き更新操作も提供するものに拡張します。

boolean compareAndSet(expectedValue, updateValue);

以下の投稿の@teto answerを参照してください:

揮発性ブール値vs AtomicBoolean

0
Ravindra babu