1

マルチスレッド プログラミングを行っているときに、有線の問題が発生しました。オブジェクトの更新は、別のスレッドで部分的にしか表示されません。擬似コードは次のとおりです。

初期状態: スレッド A が実行中で、スレッド B がブロックされている

Class C {
    public int i;
    public String s;
}

スレッド A:

...
// c is an object of class C and is accessible by both thread A and B
c.i = 10;
c.s = "success";
wakeup thread B:

スレッド B:

// after wakeup
assert(c.i == 10);
assert(c.s.equals("success"));

問題は次のとおりです。スレッド B では、文字列 cs の値が実際には null になることがあります。しかし、私はそれが「成功」という価値を持つことを期待しています。一方、アサート ステートメントの前に Thread.sleep(sometime) を配置すると、cs の期待値が表示されますが、なぜそれが発生するのかわかりません。

フィールド変数 s を volatile として宣言しようとしましたが、役に立ちません。

ありがとう!

更新 すべての返信/回答に感謝します。さらに実験と調査を行った結果、使用しているフレームワークのバグであると確信しています。フレームワークはスレッドの一時停止/再開を管理し、多数の同時要求/接続 (10k スレッドなど) があると混乱します。

4

4 に答える 4

3

マルチスレッドを使用している場合は、すべてのスレッドを共有しますCPU。どのスレッドが前に完了し、どのスレッドが最後に完了するかはわかりません。Thread最後に開始したものが最初に終了する可能性があります。CPUそれはすべて、使用されるスケジューリングアルゴリズムに依存します。

したがって、2つのスレッドを呼び出しずにsleep、またはwaitそれらのいずれかで実行している場合(tahtはそれらのinterruptingいずれもなし)、CPU割り当ては両方の間で切り替わりThreadsます。したがって、が完了Thread Bする前でもCPUを取得することは確かに可能です。Thread A

ただし、ジョブを完了するのにThread B十分な時間スリープ状態になると、その時間までスレッドAに割り当てられます。したがって、ジョブを完了するのに十分な時間があります(ただし、スレッドが2つしかなく、その時点で状態になっている場合)ACPUABrunnable

そのため、multithreadingコードの結果は決して同じではありません。それは複数の実行で変化し続けます。したがって、コードをしばらく実行すると10 - 15。この違いがわかります。

を確実にThread A完了するために、を使用している特定のインスタンスでをThread B呼び出すことができwaitます。次に、完了すると、ジョブが完了したことを通知するために呼び出し、続行できます。Thread BThread AThread AnotifyThread BThread B

于 2012-10-26T05:26:33.533 に答える
3

スレッド A と B の間で何らかの同期が必要です。

スレッド A:

c.i = 10;
c.s = "success";
c.notify()

スレッド B:

c.wait()
assert(c.i == 10);
assert(c.s.equals("success"));

この同期 (またはsynchronizedブロックなどの同等のもの) がなければ、あるスレッドから別のスレッドへの書き込みが (まったく、または特定の順序で) 行われたことが保証されません。

于 2012-10-26T05:28:34.547 に答える
1

マルチスレッド アプリケーションでは、各 CPU にローカル メモリ キャッシュがあり、メモリ操作は最適化のために大幅に並べ替えられます。Cスレッド間で共有されるインスタンスが であることを確認する必要がありますsynchronized。これにより、1 つのスレッドだけが操作を実行できるようになり両方のスレッドがオブジェクトの最新のメモリ バージョンを使用するようになります。

キーワードを使用している場合、オブジェクトsynchronizedで同期するのが一般的です。final

  // shared by both threads
  final C c = new C();
  ...

スレッド A:

  ...
  // this allows us to notify on c _and_ synchronizes memory
  synchronized (c) {
     c.i = 10;
     c.s = "success";
     // signal the other thread that is wait-ing
     c.notify();
  }

スレッド B:

  // this allows us to wait for C _and_ synchronizes memory
  synchronized (c) {
     // it's common to test for wait in while loop cause of "spurious interrupts"
     while (c.s == null) {
        // wait for c to be updated
        c.wait();
     }
  }
  assert(c.i == 10);
  assert(c.s.equals("success"));

Cオブジェクトが ThreadA によって構築されている場合、代わりに A と B の両方の final を定義して、代わりに同期することができますObject lock = new Object();。A と Bは、待機/通知が機能するために同じオブジェクト参照で同期する必要があるため、変更中のオブジェクトで同期しないでください。

フィールド変数 s を volatile として宣言しようとしましたが、役に立ちません。

両方が揮発性である場合、これc.i は機能する はずですが、A と B の間でシグナリングがどのように行われたかによって異なります。また、オブジェクトが変更されている場合は、それ自体の定義も揮発性にする必要があります。ここでのキーワードは、シグナリングとメモリの同期を処理します。c.sBcC csynchronized

お役に立てれば。

于 2012-10-26T11:46:00.773 に答える
1

volatile を使用すると、質問が解決されます。たとえば、あなたの場合、次のことができます。

class C {
    public int i;
    volatile public String s;
}

volatile 変数を宣言すると、次のようになります。この変数の値は、スレッド ローカルにキャッシュされることはありません。すべての読み取りと書き込みは、「メイン メモリ」に直接行われます。変数へのアクセスは、それ自体で同期された同期ブロックに囲まれているかのように機能します。

試してみる!

于 2012-10-26T12:02:00.413 に答える