4

私は1つ持っていますthread1

if(object != null){
   object.play();
}

もう 1 つはいつでも参照にthread2書き込むことができますnullobject

これらのスレッドを同時に実行します。チェック後に参照thread2を書き換えることができ、それがスローされることはわかっています。チェック後に参照を書き換えることは可能ですか?objectnullNullPointerExceptionthread2objectNullPointerException

4

7 に答える 7

6

NullPointerException チェック後に thread2 がオブジェクト参照を書き換えることは可能ですか?

絶対に -メソッドの実行object中にの値を変更する可能性があります。play()それ自体はエラーにはなりません。

同期やその他のメモリ バリアがなければ、スレッド 2 はobject不確定な期間、スレッド 1 が気付かないうちに の値を変更する可能性があることに注意してください。

コードのより大きな目的に関する他の知識がなければ、何をすべきかを言うのは困難です。

于 2012-10-08T12:34:32.957 に答える
5

簡単なsynchronized例:

/**
To maintain thread safety, only access this through getter and setter
or other synchronized method
**/
private ObjectType object;

public synchronized void setObject(ObjectType object) {
  this.object = object;
}

public synchronized ObjectType getObject() {
  return object;
}

public void doPlay() {
  final ObjectType obj = getObject();
  //here, thread 2 can change "object", but it's not going to affect this thread
  //as we already safely got our reference to "object" in "obj".
  if(obj != null){ 
   obj.play(); 
  }
}

public synchronized void alterativeDoPlay() {
  //the difference here is that another thread won't be able to change "object"
  //until the object's play() method has completed.
  //depending on the code in play, this has potential for deadlocks, where as
  //the other `doPlay` has zero deadlock potential.
  if(object != null){
   object.play(); 
  }
}
于 2012-10-08T12:54:24.907 に答える
1

objectが複数のスレッドから変更できるインスタンス変数または静的変数の場合、その値は、ステートメントでテストしてからそのインスタンス メソッドを呼び出すまでの間に変化する可能性がありますif

次のようにオブジェクトをローカル変数にコピーすることで、この問題を回避するようにコードを変更できます。

Playable objectCopy = object;
if(objectCopy != null) {
    objectCopy.play();
}

はローカル変数であるためobjectCopy、その値はテストと の呼び出しの間で変更できませんplay。もちろんプレイアブルオブジェクト自体の状態が変化することもありますが、それはnullチェックで直せるものではありません。

于 2012-10-08T12:40:05.333 に答える
1

ここでCountDownLatchを使用できます。Thread1 は Thread2 によるカウントダウンを待機し、thread2 でタスクを実行してカウントダウンを停止できます。

コードスニペット -

CountDownLatch latch = new CountDownLatch(1);
new Thread1(latch).start();
new Thread2(latch).start();
public class Thread1 extends Thread {
  private final CountDownLatch startLatch;

  public Thread1(CountDownLatch startLatch) {
    this.startLatch = startLatch;
  }
  public void run() {
    try {
      startLatch.await();
      // ... perform task
    } catch (InterruptedException iex) {}
  }
}

public class Thread1 extends Thread {
  private final CountDownLatch stopLatch;

  public Thread1(CountDownLatch stopLatch) {
    this.stopLatch = stopLatch;
  }
  public void run() {
    try {
      // perform task
    } finally {
      stopLatch.countDown();
    }
  }
}
于 2012-10-08T12:35:02.360 に答える
1

ブライアンの法則によると:

When we write a variable, which next has to be read by another thread, or when we are reading a variable which has lately been written by another thread, then use synchronization. Synchronize the atomic statements or getter/setters which has access to the crucial state of data with the same monitor lock.

-を使用しsynchronizationます。

-CountDownLatchから使用できますjava.util.concurrent

于 2012-10-08T12:45:10.747 に答える
0

私の教授が言ったように、「並行性はかなり不安定な男です。私たちは彼に何を期待するかわかりません。」あなたの質問に来る:

NullPointerExceptionチェックの後にthread2がオブジェクト参照を書き換えることは可能ですか?

はい

Thread2は、thread1が1回発生する間に、オブジェクトに何度もアクセスできます。またはその逆。thread2がオブジェクトにアクセスしている間、thread1が多数発生する可能性があります。

シンプルに使うなら

System.out.println();

コードの多くの場所で、NullPointerExceptionエラーの後にコンソールの出力が表示されることに気付く場合があります(キャッチされなかった場合)。

于 2012-10-08T12:47:39.767 に答える
0

この問題を解決するには、何らかの形式の同期プリミティブを使用する必要があります。こちらの「同期ステートメント」を参照してください。あなたの場合、ifブロック全体と、使用または更新するスレッド内の任意の場所をラップする必要がありますobject2

于 2012-10-08T12:37:04.173 に答える