notifyall()プロファイリング中の呼び出しの違いの数
-
28-10-2019 - |
質問
JVMTIを使用してシンプルなプロファイラーを実装して、の呼び出しを表示しました wait()
と notifyAll()
. 。テストケースとして、私は使用しています。 Oracleのプロデューサー消費者の例. 。次の3つのイベントがあります。
- notifyall()が呼び出されます
- wait()が呼び出されます
- wait()が残っています
wait()
呼び出しとその去ったとき、イベントを使用してプロファイルしました MonitorEnter
と MonitorExit
. 。 notifyAll()
呼び出しは、名前のメソッドの場合にプロファイルされます notifyAll
退出しました。
今、私は次の結果を持っています 最初はプロファイラーからです それ自体と 2番目はJavaからです, 、私が適切なものを置いた場所 System.out.println
声明。
// Profiler:
Thread-1 invoked notifyAll()
Thread-0 invoked notifyAll()
Thread-0 invoked notifyAll()
Thread-0 invoked notifyAll()
Thread-0 invoked notifyAll()
Thread-0 invoked notifyAll()
Thread-1 invoked notifyAll()
Thread-1 invoked notifyAll()
Thread-1 invoked notifyAll()
Thread-1 invoked notifyAll()
Thread-1 invoked notifyAll()
Thread-1 invoked notifyAll()
Thread-1 invoked notifyAll()
Thread-1 invoked wait()
Thread-1 left wait()
Thread-1 invoked notifyAll()
Thread-1 invoked wait()
Thread-1 left wait()
Thread-1 invoked notifyAll()
Thread-1 invoked wait()
Thread-1 left wait()
Thread-1 invoked notifyAll()
// Java:
Thread-0 invoked notifyAll()
Thread-1 invoked notifyAll()
Thread-0 invoked notifyAll()
Thread-1 invoked notifyAll()
Thread-0 invoked notifyAll()
Thread-1 invoked wait()
Thread-1 invoked notifyAll()
Thread-0 invoked notifyAll()
Thread-1 invoked wait()
Thread-1 invoked notifyAll()
Thread-0 invoked notifyAll()
Thread-1 invoked wait()
Thread-1 invoked notifyAll()
誰かがこの矛盾が何から来たのかについて説明しましたか? notifyAll()
何度も呼ばれています。これは、Javaのオペレーティングシステムへの要求からの偽陽性の反応が原因である可能性があると言われました。
a notifyAll()
リクエストはオペレーティングシステムに送信され、虚偽の陽性応答が送信されます。そこでは、リクエストが成功したようです。以来 notifyAll
ではなくプロファイリングメソッドの呼び出しによって記録されます MonitorEnter
なぜこれが待っていないのかを説明できます。
私は言うのを忘れていました、私はプログラムを個別に実行しませんでした、両方のログは同じ実行からのものです。
ADITIONAL情報
もともと答えとして追加された、Extraneonによって質問に移されました:
私はどこで見つけたと思います いくつか 追加のNotifyAllが出てくると、notifyallが呼び出されるメソッドコンテキストのプロファイリングを追加しました。
723519: Thread-1 invoked notifyAll() in Consumer.take
3763279: Thread-0 invoked notifyAll() in Producer.put
4799016: Thread-0 invoked notifyAll() in Producer.put
6744322: Thread-0 invoked notifyAll() in Producer.put
8450221: Thread-0 invoked notifyAll() in Producer.put
10108959: Thread-0 invoked notifyAll() in Producer.put
39278140: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
40725024: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
42003869: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
58448450: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
60236308: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
61601587: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
70489811: Thread-1 invoked notifyAll() in Consumer.take
75068409: Thread-1 invoked wait() in Drop.take
75726202: Thread-1 left wait() in Drop.take
77035733: Thread-1 invoked notifyAll() in Consumer.take
81264978: Thread-1 invoked notifyAll() in Consumer.take
85810491: Thread-1 invoked wait() in Drop.take
86477385: Thread-1 left wait() in Drop.take
87775126: Thread-1 invoked notifyAll() in Consumer.take
しかし、これらの外部呼び出しがなくても、printfデバッグには表示されないnotifyallコールのpltenyがあります。
解決
分析に時間を費やしました プロデューサー消費者 OracleおよびOutput(Profiler and Javaプログラム)によって提供される例。いくつかの予期しないもの以外に、出力にいくつかの奇妙なことがあります notifyAll()
:
wait()メソッドが4回実行することを期待する必要があります(
String
プロデューサーによって操作される配列には4つの要素があります)。プロファイラーの結果は、3回しか実行されなかったことを示しています。非常に奇妙なもう1つのことは、プロファイラーの出力のスレッドの番号付けです。この例には2つのスレッドがありますが、プロファイラーは1つのスレッドですべてのコードを実行します。
Thread-1
, 、 その間Thread-0
実行するだけですnotifyAll()
.提供されたコードの例は、同時の観点と言語の観点から正しくプログラムされています。
wait()
とnotifyAll()
モニターを制御するための同期方法があります。待機状態はa内ですwhile
通知を使用したループは、メソッドの最後に正しく配置されます。しかし、私はそれに気づきましたcatch (InterruptedException e)
ブロックは空です。つまり、待機しているスレッドが中断された場合、notifyAll()
メソッドが実行されます。これは、いくつかの予想外の原因になる可能性がありますnotifyAll()
.
結論として、コードでいくつかの変更を実行して追加のテストを実行することなく、問題がどこから来たのかを把握するのは簡単ではありません。
サイドノートとして、このリンクを残します JVMTIを使用したデバッグおよびプロファイリングエージェントの作成 jvmtiで遊びたいという好奇心が強い人のために。
他のヒント
コードにレース条件がある場合、プロファイラーはコードを十分に遅くして、コードにエラーを表示または非表示にすることができます。 (レースの条件を表示するためだけに、プログラムをプロファイラーで実行するのが好きです。)
notifyall()はwait()ingスレッドのみに通知するように、notifyall()がnotifyを欠いている可能性が高い後、wait()を呼び出します。すなわち、そのステートレス、それはあなたが以前にNotifyに電話したことを知りません。
アプリケーションを遅くすると、wait()が開始されるまでnotifyall()を遅延させることができます。