1

オブジェクトが 2 つのスレッド (メイン スレッドとモニター スレッド) 間で共有される、以下のようなコードがあります。MyObject をグローバルに宣言しvolatile、確実にメモリにプッシュされるようにする必要がありますか? それ以外の場合、ifMyObject がスレッドによってローカルにのみアクセスされ、揮発性と宣言されていない場合、ステートメントは「Not null」を出力できますよね?

public static void main(String[] args) {
    MyObject obj = MyObjectFactory.createObject();
    new Monitor(obj).start();
    Thread.sleep(500); 
    if(obj == null) 
        System.out.println("Null");
    else
        System.out.println("Not null");
}

public void doSomethingWithObject(MyObject obj) {
    obj = null;
}

private class Monitor extends Thread {
   public Monitor(MyObject obj) {
       this.obj=obj;
   } 
   public void run() {
       doSomethingWithObject(obj);
   }
}

注: このコード例は、Stackoverflow で自分で書いたものであるため、コンパイルできない場合があります。疑似コードと実際のコードが混在していると考えてください。

4

4 に答える 4

2

インスタンスは共有されていますが、インスタンスへの参照は共有されていません。例:

 String a = "hello";
 String b = a;

 b = null; // doesn't affect a

abは同じインスタンスへの参照です。1つの参照を変更しても、インスタンスまたは同じインスタンスへの他の参照には影響しません。

したがって、スレッド間で状態を共有する場合は、次のフィールドを作成する必要があり MyObjectますvolatile

class MyObject { public volatile int shared; }


public void doSomethingWithObject(MyObject obj) {
    obj.shared = 1; // main() can see this
}

volatile一部のタイプ(参照およびを除くすべてのプリミティブ)でのみ機能することに注意してくださいlongこれは間違いやすいので、のタイプを確認する必要がありますjava.util.concurrent.atomic

[編集]私が上で言ったことは正しくありません。代わりに、volatilewithを使用すると、Java5以降longで期待どおりに機能します。これは、このタイプのアトミック読み取り/書き込みを保証する唯一の方法です。参考のためにこの質問を参照してください:volatile longを使用することに意味はありますか?

称賛はそれを指摘するためにAffeに行きます。ありがとう。

于 2012-09-13T07:06:01.903 に答える
1

オブジェクトにアトミックに読み取り-更新-書き込みスキームを実行させたい場合は、volatileそれをカットしないでください。同期を使用する必要があります。

ボラティリティは、変数が現在のスレッドにキャッシュされないことを保証しますが、変数が予期しないものになる可能性があるため、同時更新から変数を保護しません。

IBMのdeveloperWorksには、このテーマに関する有用な記事があります。

于 2012-09-13T07:05:40.690 に答える
1

Monitorこの例は、で作成および実行される1つのスレッドのみで構成されていmain()ます。

「メモリに確実にプッシュされるように揮発性にしますか?」-逆に、変数を揮発性として宣言すると、スレッドローカルメモリに「プッシュ」(キャッシュ)されないことが保証されます。これは、変数の値を変更する他のスレッドが存在する可能性があるためです。

変数の正しい値を確実に出力するには、メソッドを同期する必要がありますdoSomethingWithObject(メソッドのシグネチャを次のように変更します)。

public synchronized void doSomethingWithObject(MyObject obj)

または、同期ブロックを作成します。

obj = null;

this.obj=obj;
于 2012-09-13T07:06:07.820 に答える
1

nullif チェックの前にオブジェクトが確実に設定されるようにするには、オブジェクトを同期する必要があります。volatile に設定すると、変更が他のスレッドからすぐに「見える」ようになりますが、doSomethingWithObject呼び出しの前に if チェックが実行される可能性が非常に高くなります。

于 2012-09-13T07:06:57.043 に答える