首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在创建java.util.logging.Logger之前,如何检查它是否已经存在?

在创建java.util.logging.Logger之前,如何检查它是否已经存在?
EN

Stack Overflow用户
提问于 2012-07-03 17:07:48
回答 2查看 8.8K关注 0票数 1

我遇到了一个java.util.logging死锁,我怀疑这个死锁与我在(可能)创建Logger之前检查它是否存在有关。

我的问题是:在创建Logger**'s之前,以线程安全的方式检查存在的最佳方式是什么,同时阻止其他线程无意中创建** Logger

背景:java.util.logging.Logger#getLogger(String, String)将(以线程安全的方式,原子化地)查找一个命名的Logger,如果不存在,则创建它。但在我的例子中,我想在着手进行一些复杂的ResourceBundle定位/修复之前,检查Logger是否已经存在。然后,在我的ResourceBundle设置好之后,并且我知道它是有效的,我想把它的名字提供给Logger#getLogger(String, String)调用。

只有在确实不存在ResourceBundle的情况下,我才需要进行此Logger定位/修复。我需要让这一切以原子的方式发生,这样在我设置ResourceBundle-I的过程中,其他线程就不会执行ResourceBundle调用--例如,不要让另一个线程潜入其中,使用不同的ResourceBundle名称,从而使我所有的辛勤工作都无效。

我的成语是这样的:

代码语言:javascript
复制
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;

这导致了僵局。

当我的代码锁定在全局LogManager上时,另一个线程无害地执行一个完全无关的Logger.getLogger(name)调用,从而获得了Logger.class对象的锁(Logger#getLogger(String, String)是一个staticsynchronized方法)。因此,这个线程具有Logger.class...which的锁,我的线程(如上面所示)需要运行他的Logger.getLogger(name, resourceBundleName)调用。在内部,Logger.getLogger(name)抢占全局LogManager的锁。瞧。死锁。

我认为防止这种情况的方法是遵循以相同顺序获取所有锁的悠久传统。据我所知,简单地用另一个synchronized块包围我的synchronized块--但这一次在Logger.class-should上做到了这一点。这听起来对吗?这就是:

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

感谢您的时间和关注!

EN

回答 2

Stack Overflow用户

发布于 2012-07-03 18:33:33

不要锁定您无法控制的对象;这会导致问题。或者,您可以使用您控制的另一个对象,例如Map<String, Logger>。您可以使用普通的java.util.HashMap<String, Logger>synchronized块,就像使用日志管理器一样。

代码语言:javascript
复制
// 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);
    }
}
票数 1
EN

Stack Overflow用户

发布于 2012-07-03 18:16:53

由于getLoggeraddLogger调用已经为您同步,所以我不认为同步该块会给您带来任何好处。我只想删除同步。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11315798

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档