52

変数が元々揮発性であると宣言されている間に、コードのブロックで同期を行って変数を変更するJavaの例をいくつか見ました。一意のインスタンスを揮発性として宣言し、ブロックを同期したシングルトンクラスの例で見ました。それはそのインスタンスを初期化します...私の質問は、同期中にそれを揮発性と宣言する理由、なぜ両方を行う必要があるのか​​ということです。それらの1つは他のために十分ではありませんか?

public class SomeClass {
    volatile static Object uniqueInstance = null;

    public static Object getInstance() {
        if (uniqueInstance == null) {
            synchronized (someClass.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new SomeClass();
                }
            }
        }
        return uniqueInstance;
    }
}

前もって感謝します。

4

5 に答える 5

24

この場合、最初のチェックが同期ブロック内にある場合は、同期だけで十分です (ただし、そうではなく、変数が揮発性でない場合、あるスレッドが別のスレッドによって実行された変更を認識しない可能性があります)。複数の操作をアトミックに実行する必要があるため、揮発性だけでは十分ではありません。しかし、注意してください!ここにあるのは、いわゆるダブルチェック ロックです。これは一般的なイディオムですが、残念ながら確実には機能しません。これは Java 1.6 から変更されたと思いますが、それでもこの種のコードは危険な場合があります。

EDIT : 変数が volatile の場合、このコードは JDK 5 (以前に書いた 6 ではありません) 以降は正しく機能しますが、JDK 1.4 以前では期待どおりに機能しません。

于 2012-03-12T10:39:45.957 に答える
7

if(uniqueInstance == null)これは、ダブル チェック ロックを使用します。同期されたパーツ内にないことに注意してください。

揮発性でない場合、部分的に構築されたオブジェクトで「初期化」されている可能性があり、その一部はブロックuniqueInstanceで実行されているスレッド以外には表示されません。synchronizedこの場合、volatile はこれを全か無かの操作にします。

同期ブロックがなければ、2 つのスレッドが同時にこの時点に到達する可能性があります。

if(uniqueInstance == null) {
      uniqueInstance = new someClass(); <---- here

そして、目的に反する 2 つの SomeClass オブジェクトを作成します。

厳密に言えば、 volatile は必要ありません。メソッドは

public static someClass getInstance() {
    synchronized(FullDictionary.class) {
         if(uniqueInstance == null) {
             uniqueInstance = new someClass();
          }
         return uniqueInstance;
    }
}

ただし、getInstance() を実行するすべてのスレッドの同期とシリアル化が発生します。

于 2012-03-12T10:44:27.253 に答える
6

この投稿では、volatile の背後にある考え方について説明します。

また、重要な研究であるJava Concurrency in Practiceでも取り上げられています。

主な考え方は、並行性には共有状態の保護だけでなく、スレッド間のその状態の可視性も含まれるということです。ここで volatile の出番です (このより大きなコントラクトはJava メモリ モデルで定義されています)。

于 2012-03-12T10:43:19.733 に答える
0

同期ブロックを使用せずに同期を行うことができます。その中で揮発性変数を使用する必要はありません...揮発性はメインメモリから1つの変数を更新します..同期メインメモリからアクセスされたすべての共有変数を更新します..したがって、要件に応じて使用できます..

于 2012-03-12T10:46:18.793 に答える