2

スレッド 1 に次のコードがあります。

synchronized (queues.get(currentQueue)) {            //line 1
   queues.get(currentQueue).add(networkEvent);       //line 2
}

およびスレッド2の以下:

synchronized (queues.get(currentQueue)) {
   if (queues.get(currentQueue).size() > 10) {
      currentQueue = 1;
   }
}

ここで私の質問に: currentQueue 変数の値は現在 0 です。スレッド 2 が currentQueue の値を 1 に変更し、スレッド 1 が行 1 で待機する場合 (同期のため)、スレッド 1 は更新された currentQueue 値を行で使用しますか? 2 スレッド 2 が終了した後 (それが私がしたいことです)。

4

3 に答える 3

2

あなたの質問に対する正しい答えは次のとおりです。結果は未定義です。

モニター オブジェクトは queues.get(currentQueue) ですが、currentQueue が可変であるため、モニターも可変であるため、現在の状態は多かれ少なかれランダムです。事実上、このコードは最終的に壊れます。

それを修正する簡単な方法は、次のような関数です。

protected synchronized QueueType getCurrentQueue() {
  return queues.get(currentQueue);
}

しかし、これはまだすべてを実装する悪い方法です。並行キュー (ConcurrentLinkedQueue など) を使用して同期を完全に排除するか、ロック/最終モニター オブジェクトを操作する必要があります。

final Object queueLock = new Object();
...
synchronized(queueLock) {
  queues.get(currentQueue).add(networkEvent);
}

アクセスするたびに、queuesまたはcurrentQueue両方が使用しているデータセットを定義するときに、そのロックを使用する必要があることに注意してください。

于 2013-10-12T18:31:07.573 に答える
2

質問に対する答えは、場合によるということです。currentQueue 変数をインクリメントするコードのチャンクが他にもあると思います。この場合、ロックは ' currentQueue ' 変数ではなく、' queues ' のコレクションでも発生していませんが、'キューのコレクション。

したがって、両方のスレッドがたまたま同じキュー (キュー 5 など) にアクセスした場合、質問に対する答えは「はい」です。ただし、それが発生するのは 10 分の 1 の確率です (x の確率で 1 つ、x = ' queues ' コレクション内のキューの数)。したがって、スレッドが異なるキューにアクセスする場合、答えはノーです。

于 2013-10-12T18:36:08.407 に答える
1

他のスレッドが currentQueue の値を変更しないと仮定すると、はい、同期の本体で queues.get(currentQueue) をもう一度呼び出しているため、スレッド 1 はcurrentQueueの更新された値が指すキューを使用することになりますブロック。ただし、これは同期が健全であることを意味するものではありません。現在のキューにアクセスするための共有キーのように見えるため、実際には currentQueue で同期する必要があります。

また、synchronize を使用する場合は、変数の値ではなく、変数の参照で同期していることを覚えておいてください。そのため、新しいオブジェクトを再割り当てすると、同期が意味をなさなくなります。

于 2013-10-12T18:33:36.747 に答える