31

この質問のポイントは、Javaが期待どおりに機能していないことを説明することです。

次のコードがどのように動作することを期待しますか?

public class SynchTester {
  private static SynchTester synchTester;

  public synchronized static SynchTester getSynchTester(){
    if(synchTester==null){
      synchTester = new SynchTester();
    }

    return synchTester;
  }

  private SynchTester() {
    SynchTester myTester = getSynchTester();
  }

  public static void main(String[] args) {
    SynchTester tester = SynchTester.getSynchTester();
  }
}

再帰が完了するのを待っているデッドロックでハングすることを期待しますが、代わりにStackOverflowをスローします。明らかに同期されても、同じスレッドへのアクセスはブロックされません。

これはバグですか?

4

3 に答える 3

78

Javaでは、同期ロックは再入可能です。

スレッドが別のスレッドが所有するロックを取得できないことを思い出してください。ただし、スレッドはすでに所有しているロックを取得できます。スレッドが同じロックを複数回取得できるようにすると、再入可能な同期が有効になります。これは、同期されたコードが直接的または間接的に、同期されたコードも含むメソッドを呼び出し、両方のコードセットが同じロックを使用する状況を示しています。再入可能な同期がない場合、同期されたコードは、スレッドがそれ自体をブロックしないようにするために、多くの追加の予防措置を講じる必要があります。

出典:このページの下部を参照

于 2012-11-02T15:09:27.883 に答える
3

同期されたメソッドは、モニターオブジェクトをロックできる必要があります。モニターオブジェクトはインスタンス(または静的メソッドのクラス)です。すでにロックされているスレッドは、再度ロックを取得する必要はありません。そうです、それはスタックオーバーフロー(harhar)を引き起こす可能性があります。

于 2012-11-02T15:07:58.503 に答える
3

Javaチュートリアルから:

1つのスレッドがオブジェクトの同期メソッドを実行している場合、同じオブジェクトブロックの同期メソッドを呼び出す他のすべてのスレッドは、最初のスレッドがオブジェクトで完了するまで実行を一時停止します。

したがって、syncronizedキーワードは期待どおりに機能し、同期された再帰呼び出しはJavaでは完全に合法(および機能)であると思います。

于 2012-11-02T15:09:20.973 に答える