1
public class Test{
   private MyObj myobj = new MyObj(); //it is not volatile


   public class Updater extends Thred{
      myobje = getNewObjFromDb() ; //not am setting new object
   }

   public MyObj getData(){
    //getting stale date is fine for 
    return myobj;
   }


}

定期的に更新 myobjを更新
他のクラスは getData を使用してデータをフェッチ
volatile キーワードを使用せずにこのコードはスレッドセーフですか?
私はイエスと思う。誰か確認できますか?

4

6 に答える 6

7

いいえ、これはスレッドセーフではありません。(そう思う根拠は?)

あるスレッドで変数を更新し、別のスレッドから読み取る場合は、書き込みと後続の読み取りの間に発生前の関係を確立する必要があります。

つまり、これは基本的synchronizedに、(同じモニターで) 読み取りと書き込みの両方を行うか、参照を行うことを意味しますvolatile

それがなければ、読み取りスレッドが更新を確認するという保証はありません。また、「古い値または新しい値のいずれかが表示される」ほど単純ではありません。リーダー スレッドは、結果的にデータの破損を伴う非常に奇妙な動作を確認する可能性があります。たとえば、同期の欠如が無限ループを引き起こす可能性があることを確認してください(その記事へのコメント、特に Brian Goetz のコメントは読む価値があります)。

話の教訓: 変更可能なデータがスレッド間で共有されるときはいつでも、同期を適切に使用しないと (つまり、共有変数へのすべてのアクセス、読み取りまたは書き込みを保護するために共通のロックを使用することを意味します)、プログラムは壊れ、壊れます。おそらく列挙することさえできない方法で。

于 2012-10-23T14:32:06.777 に答える
1

古い参照を取得する可能性があります。無効な参照を取得することはできません。取得する参照は、変数が指す、または指す、または指すオブジェクトへの参照の値です。

参照がどれだけ古くなっているかは保証されませんが、それでも一部のオブジェクトへの参照であり、そのオブジェクトはまだ存在していることに注意してください。言い換えると、参照の書き込みはアトミックです(書き込み中には何も起こり得ません)が、同期されません(命令の並べ替え、スレッドローカルキャッシュなどの対象となります)。

参照をとして宣言する場合はvolatile、変数の周囲に同期ポイントを作成します。簡単に言えば、これはアクセススレッドのすべてのキャッシュがフラッシュされることを意味します(書き込みは書き込まれ、読み取りは忘れられます)。

アトミックな読み取り/書き込みを取得しないタイプはlongdouble32ビットマシンでは32ビットより大きいためです。

于 2012-10-23T14:48:49.970 に答える
1

不変 (すべてのフィールドが final) の場合MyObj、volatile は必要ありません。

于 2012-10-24T05:41:27.297 に答える
1

いいえ、そうではありません。

がないと、別のスレッドからvolatile呼び出すとgetData()、古いキャッシュ値が返される場合があります。
volatile1 つのスレッドからの割り当てが、他のすべてのスレッドですぐに見えるように強制します。

オブジェクト自体が不変でない場合は、他の問題が発生する可能性があることに注意してください。

于 2012-10-23T14:30:56.567 に答える
0

この種のコードの大きな問題は、遅延初期化です。volatileまたはsynchronizedキーワードがないと、完全に初期化されていない新しい値を割り当てることができますmyobj。Javaメモリモデルでは、オブジェクトコンストラクタが戻った後にオブジェクト構築の一部を実行できます。このメモリ操作の並べ替えが、マルチスレッドの状況でメモリバリアが非常に重要である理由です。

MyObjメモリバリアの制限がなければ、発生前の保証はないため、が完全に構築されているかどうかはわかりません。これは、別のスレッドが部分的に初期化されたオブジェクトを使用していて、予期しない結果になる可能性があることを意味します。

コンストラクターの同期に関する詳細は次のとおりです。

Javaでのコンストラクターの同期

于 2012-10-23T15:05:32.837 に答える
0

Volatile はブール変数では機能しますが、参照では機能しません。Myobj は、AtomicReference で動作するキャッシュ オブジェクトのように動作するようです。コードは DB から値を抽出するので、コードをそのままにして、AtomicReference を追加します。

import java.util.concurrent.atomic.AtomicReference;

    public class AtomicReferenceTest {
        private AtomicReference<MyObj> myobj = new AtomicReference<MyObj>();

        public class Updater extends Thread {

            public void run() {
                MyObj newMyobj = getNewObjFromDb();
                updateMyObj(newMyobj);
            }

            public void updateMyObj(MyObj newMyobj) {
                myobj.compareAndSet(myobj.get(), newMyobj);
            }

             }
        public MyObj getData() {
             return myobj.get();
        }
    }

    class MyObj {
    }
于 2012-10-24T17:20:46.583 に答える