2012-02-10 18 views
2

質問:モニターが既にロックされているときに同期ブロックを再入力するコストはいくらですか?例えば同期ブロックを再入力するコスト

Object lock; 
void outer() 
{ 
    synchronized (lock) 
    { 
     innerOne(); 
     innerTwo(); 
    } 
} 

void innerOne() { synchronized (lock) { /* ... */ } } 
void innerTwo() { synchronized (lock) { /* ... */ } } 

上記の目的は、スレッドがlockに同期させながらinnerOneinnerTwoが常に呼び出されることです。

コストが無視できない場合、assertステートメントを実行するために呼び出すことのできる方法はありますか?最も近いのは、lock.notify()に電話し、IllegalMonitorStateExceptionをキャッチすることです。同じように使用されるだろう

boolean isMonitorHeld(final Object object) 
{ 
    try { object.notify(); return true } 
    catch (final IllegalMonitorStateException e) { return false; } 
} 

void innerOne() { assert isMonitorHeld(lock); /* ... */ } 

には、2つのオプションのスタイル上の任意のコメント、またはいずれかの選択肢がありますか?

EDIT

私はちょうどより多くの包括的な答えは「時間にそれをして見る」願っています。コードに遭遇する可能性のあるすべての状況を予見し、これらの状況を示すテストを作成する能力はありません。さまざまな状況でどのように動作するかを理解するために、同期メカニズムがどのように機能するかを理解したいと思います。私は、さまざまなプラットフォームで異なる方法で同期を実装できることを理解しています。どのような場合には(主にSolarisとLinux OSで)違いますか?

私は直感的に、私が見つけることができるほとんどの記事が同期していないロックが安価であることを暗示しているので、同期ブロックを再入力するとコストが顕著になるとは思わない。しかし、これらの方法では、と呼ばれる印象を与えるので、ロックで最初に同期されたがなくても、同期されたブロックを追加することは適切ではありません。断言は意図のより良い考えを与えるが、それはかなり醜いハックのように見える。より正当な選択肢がないという正当な理由があるかどうかを知りたいのですが。

+1

なぜ測定しないのですか?あなたが違いを測ることができないなら、それはないのです。 – skaffman

答えて

4

あなたの質問は1つのことを尋ねているので、あなたの質問の本文が何かを求めています。スレッドがロックを保持しているかどうかをテストするアルゴリズムは、非常に遅いと言うことができます。チェックしないだけでなく、はるかに遅くなります。このような例外を投げるのは高価です。例外に関するルール1。 プログラムで通常のフロー制御の例外を使用しないでください。例外で、制御フロー構造の形式ですが、エラーフロー制御にのみ使用してください。主に例外を投げるたびにスタックトレースを収集して例外に配置する必要があるためです。それは高価な操作です。あなたは間違いなく例外を使うべきですが、それはエラーフロー制御のために設計されたものだけです。

currentThreadがロックを保持しているかどうかをテストする場合は、Threadを使用する必要があります。currentThreadための同期ブロックに再入力のコストがすでに保持されているものとしてholdsLock(オブジェクトモニター)

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#holdsLock(java.lang.Object

。私はそれについて非常に詳細な答えはありません。私は、そのholdLockを呼び出すコストが何であれ、それを疑う。これはおそらく最初のチェックであり、falseを返した場合、このスレッドをこのオブジェクトモニタで待機しているスレッドのリストに追加することで、より多くのコストがかかります。それが本当であれば、それはブロックの中にすぐにジャンプする。 Javaのスレッディングは、実行したい場合は、この質問への答えは、ロック所有者のための地獄として速くする方がよいでしょう。ロックを所有していないスレッドについては、確かに高価です。正確なアルゴリズムが何であるかに対する答えがあれば、私は "Taming Threads"の本またはJava仕様でそれを賭けました。

+0

ありがとう、私は完全にスレッドメソッドを逃した。ポイントは、私は2つ以上の方法の間にいくつかの共有ロジックを持っているということです。最初のメソッドは同期を提供し、共有ロジックが実行されます。私の経験から、アサーションは開発者の意図をコードで記述するのに便利です。私の場合、モニター上で実際に同期をとると、誤った印象を受けます。なぜなら、最初にロックを取得することなくメソッドを呼び出すことができるからです。このメソッドは、最初にロックを取得せずに決して呼び出されてはなりません。そうすれば、プログラミングエラーです。 – SimonC

+0

私はあなたの質問を読んで、私は少しはっきりとしていると思います。コードの最初のセクションのように再度ロックを再取得するのではなく、2つのメソッドでassert文を使用できるかどうかを知りたいだけです。 – chubbsondubs

+0

私はメソッドがpublicであればそれをしませんが、assertを使ったプライベートメソッドでは呼び出し元を強制的にロックするので、もし誰かがあなたのコードをリファクタリングした場合、ロックを忘れるとcatchされます。私は、同期化されたブロックを使うのと同じことを私が賭けているのは賢明だと思います。 – chubbsondubs

2

これを測定します。私のシステムには違いがないかもしれません。あなたの上にあるかもしれません。デプロイするシステムはまだまだ違うかもしれません。