(おそらく) 作成する前に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 static
and synchronized
method.) のロックを取得したため、このスレッドはロックを保持してい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?
}
}
お時間とご関心をお寄せいただきありがとうございます。