1

だから、これはスレッドへの私の最初の進出であり、これまでのところ私は気が狂っています。私の問題は、消費者スレッドがハングする原因となるある種の同期エラーのようです。私は他のコードを調べましたが、見つけたほぼすべてのコードを調べましたが、エラーが何であるかがわかりません。また、Eclipse で実行されるコードと、コマンド ラインで javac を介して実行されるコードとの間に矛盾があるようです。

意図 - バウンド バッファ (1000 スロット) を使用して、1,000,000 個の double を作成および消費します。通知と待機のみを使用します。

問題 - Eclipse では、コンシューマ スレッドが約 940,000 回の繰り返しでハングすることがありますが、それ以外の場合は完了します。コマンド ラインでは、コンシューマ スレッドが常にハングします。

4

4 に答える 4

2

Wait()メソッドは偽の方法で (つまり、通知なしで) 中断する可能性があります。ここを参照してください。if (condition) { wait(); }したがって、すべてをに 置き換える必要がありますwhile (condition) { wait(); }。多分これが原因です。

于 2012-04-11T08:03:35.210 に答える
1

あなたはとを台無しにaddPlacegetPlaceた。わかりやすくするために、名前をとに変更しnextWriteますnextRead。これがあなたのadd()です

if ((nextWrite + 1) == nextRead) {
  wait();
}
buff[nextWrite] = someRandomNumber;
nextWrite = (nextWrite + 1) % 1000;
notify();

そしてこれはあなたのget()です

if (nextRead == nextWrite) {
  wait();
}

論理エラーは明らかです。なぜなら、nextWriteは[0;の範囲にあるからです。999]、nextWrite + 1[1;になります。1000]ですnextReadが、[0; 999]。nextWriteis999またはnextReadisのたび 0に、wait呼び出しが実行されることはなく、プロデューサーはまだ読み取られていないデータを上書きする可能性があります。

プロデューサーはある時点で上書きを停止する場合がありますが、事実上、一方のコアがもう一方のコアよりも100万倍高速である架空のマルチコアマシンでは、プロデューサーはそれを完了してrun()終了しnextWrite + 1 == nextReadます。

nextRead私たちの架空のマシンでは、コンシューマーはになるとすぐにハングします0(つまりnextWrite、プロデューサーが最後に設定し0たのは、正確に100万回の反復を実行し、バッファーカウンターがとして定義されているためi % 1000です)。wait()プロデューサーですが、終了しているため、通知は届きません。

これは、コードの改良された(そして機能している)バージョンです。

編集 私は(些細な)解決策を忘れました:

public synchronized void add(double randomNumber) throws InterruptedException {
    if((nextWrite + 1) % 1000 == nextRead)
      wait();
    buff[nextWrite] = randomNumber;
    nextWrite = (nextWrite+1)%1000;
    notify();
}
于 2012-04-11T11:26:28.580 に答える
0

さて、私はあなたのプログラムに論理的な問題があると思います。通常のプロデュース・コンシュームでは、好きなだけプロデュースできますが、プロデュースしたものがある場合にのみコンシュームできます。

あなたの実装では、プロデュースし、消費されるまで待ってから、もう一度プロデュースします。

それはあなたが意図したことではないと思います。

add メソッドから wait() ブロックを削除し、get() メソッドから notify() を削除します。また、main ではスレッド join() は必要ないと思います。

編集: get() メソッドは常に wait() に入ります。プロデューサーがすでに仕事を終えていたとしても。考えてみてください。Producer がすでにジョブを終了している場合、notify() は取得されません。

于 2012-04-11T08:02:26.127 に答える
0

いくつかのポイント:

  • ProducerJava では、通常、最初のクラス名 char は大文字でなければなりませConsumerBuffer
  • これを Eclipse / コマンド ラインで試すということは、プロデューサーを Eclipse で実行し、コンシューマーをコマンド ラインで実行することを意味しますか、それともその逆ですか? その場合は機能bufferせず、2 つのプロセス間で共有されません。
于 2012-04-11T08:03:46.563 に答える