0

私は現在ConcurrentSkipList、Java コレクションからアクセスする高度な並行ベンチマークを実行しています。そのメソッド内でスレッドがブロックされていることがわかりました。より正確には、次のとおりです。

java.util.concurrent.ConcurrentSkipListMap.doGet(ConcurrentSkipListMap.java:828)    
java.util.concurrent.ConcurrentSkipListMap.get(ConcurrentSkipListMap.java:1626)

(これは、個々のスレッドのスタック トレースを 10 秒間隔で出力することによって得られます)。これは数分経ってもまだ解決されていません

これはコレクションの予期される動作ですか? ブロッキングが発生する可能性が高い同時の他のコレクションは何ですか?

ConcurrentHashMapテストした結果、 sで同様の動作を示します。

java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:994)
4

3 に答える 3

5

これは、誤った結果である可能性があります。

Java に現在のすべてのスタック トレースのダンプを要求すると、Java は各スレッドに、降伏点に達したときに待機するように指示し、トレースをキャプチャしてから、すべてのスレッドを再開します。ご想像のとおり、これは降伏点がこれらのトレースで過剰に表現されていることを意味します。これらには、同期されたメソッド、volatileアクセスなどが含まれます。フィールドは、でアクセスされConcurrentSkipListMap.headます。volatiledoGet

詳細な分析については、この論文を参照してください。

Solaris Studio には、OS からスタック トレースを取得して Java スタック トレースに変換するプロファイラがあります。これにより、降伏点への偏りがなくなり、より正確な結果が得られます。doGetそれがほぼ完全になくなることに気付くかもしれません。Linux で運良く実行できただけで、すぐに使えるわけではありません。興味がある場合は、コメントで設定方法を尋ねてください。喜んでお手伝いします。

より簡単な方法として、呼び出しをConcurrentSkipList.getでラップしSystem.nanoTime()て、これが本当に時間の無駄であるかどうかを確認することができます。そのメソッドにどれだけの時間を費やしているかを把握し、そのメソッドに何パーセントの時間を費やしているとプロファイラーが言っていると仮定して、それが期待どおりかどうかを確認します。

恥知らずな自己プラグイン:数か月前に職場でのプレゼンテーション用に、これを示す簡単なプログラムを作成しました。プロファイラーに対して実行すると、SpinWork.workが多く表示される一方HardWork.workで、まったく表示されないことが示されるはずです。後者は実際にはもっと時間がかかりますが。降伏点は含まれません。

于 2013-10-28T15:04:27.550 に答える
0

まあ、それは本当の形でブロックしていません。ブロッキングとは、スレッド アクティビティの一時停止を意味します。ConcurrentSkipListMap はノンブロッキングで、成功するまでスピンします。ただし、最終的には成功することも保証されます (つまり、無限ループに陥らないようにする必要があります)。

そうは言っても、非同期で多くの get と多くの put を実行していない限り、このメソッドにそれほど多くの時間を費やすことができるとは思えません。

例を使用して再作成し、私たちと共有できる場合は、それが役立つ場合があります.

于 2013-10-28T15:02:00.663 に答える
0

ConcurrentHashMap.getつまり、CPU は読み取りを実行する前に未処理の書き込みをすべて終了する必要があります。これを STORE/LOAD バリアと呼びます。他のスレッド/コアでの処理量によっては、これには長い時間がかかる場合があります。https://www.cs.umd.edu/users/pugh/java/memoryModel/jsr-133-faq.htmlを参照してください。

于 2013-10-28T15:05:59.323 に答える