1

(おそらく) 作成する前にjava.util.loggingの存在をチェックしている方法に関連していると思われるデッドロックが発生しています。Logger

私の質問は次のとおりです。 を作成する前に の存在をスレッドセーフな方法でチェックし、その間Loggerに他のスレッドによる不注意による作成をブロックする最善の方法は何ですか?Logger

背景: java.util.logging.Logger#getLogger(String, String)(アトミックに、スレッドセーフな方法で) 名前付きLoggerが存在する場合は検索し、存在しない場合は作成します。しかし、私の場合、複雑な場所の特定/親の変更Loggerを行う前に、 が既に存在するかどうかを確認したいと考えています。ResourceBundle次に、ResourceBundleセットアップが完了し、それが有効であることを確認したら、その名前をLogger#getLogger(String, String)呼び出しに提供したいと思います。

実際に aが存在しないResourceBundle場合にのみ、この検索/親の変更が必要です。セットアップ中にLogger他のスレッドが呼び出しを行わないように、このすべてをアトミックに実行する必要があります。他のスレッドがそこに忍び込んで別の名前を使用することは望ましくありません。たとえば、私のすべてのハードワークを無効にします。Logger#getLogger(String, String)ResourceBundle ResourceBundle

私が持っていたイディオムは次のようなものでした:

Logger logger = null;
final LogManager logManager = LogManager.getLogManager();
assert logManager != null;
synchronized (logManager) {
  // This method call finds the logger, but doesn't create one.
  logger = logManager.getLogger(myLoggerName);
  if (logger == null) {
    // no logger found; time to do expensive ResourceBundle lookup/parenting/etc.
    // ...time passes...
    logger = Logger.getLogger(myLoggerName, myResourceBundleNameIJustCalculated);
  }
}
assert logger != null;

これにより、デッドロックが発生しました。

私のコードが global でロックされている間にLogManager、別のスレッドが無邪気にまったく無関係なLogger.getLogger(name)呼び出しを実行し、それによってLogger.classオブジェクト ( Logger#getLogger(String, String)is a staticand synchronizedmethod.) のロックを取得したため、このスレッドはロックを保持していLogger.classます ... which my thread (上記でわかるように) )彼の Logger.getLogger(name, resourceBundleName)呼び出しを実行するために必要です。内部Logger.getLogger(name)的に、 global のロックを取得しますLogManager。出来上がり。デッドロック。

これを防ぐ方法は、すべてのロックを同じ順序で取得するという古くからの伝統に従うことだと思います。私が知る限り、私の synchronizedブロックを別の synchronizedブロックで囲むだけですが、今回はLogger.classうまくいくはずです。それは正しいと思いますか?あれは:

synchronized (Logger.class) {
  synchronized (globalLogManager) {
    // Hypothesis: this grabs locks in the same order
    // that java.util.logging classes use.  Should prevent
    // deadlocks?
  }
}

お時間とご関心をお寄せいただきありがとうございます。

4

2 に答える 2

1

自分が制御していないオブジェクトをロックしないでください。これは問題を引き起こす可能性があります。または、など、制御する別のオブジェクトを使用することもできますMap<String, Logger>。ログ マネージャーを使用しているのと同じ方法で、法線をブロックjava.util.HashMap<String, Logger>と共に使用できます。synchronized

// import java.util.*;
// import java.util.logging.*;
final static Map<String, Logger> loggers = new HashMap<String, Logger>();

Logger logger;
synchronized(loggers) {
    logger = loggers.get(myLoggerName);
    if (logger == null) {
        // ... your expensive computation ...
        logger = Logger.getLogger(myLoggerName, myResourceBundleName);
        loggers.put(myLoggerName, logger);
    }
}
于 2012-07-03T18:33:33.703 に答える
0

と のgetLogger呼び出しaddLoggerは既に同期されているため、そのブロックを同期しても何も得られないと思います。同期を削除するだけです。

于 2012-07-03T18:16:53.773 に答える