java – 从静态最终变量初始化器获取Logger是否有效?

我们有很多类代码,它们有一些如下所示的样板:
private static Logger logger = null;

private static Logger getLogger() {
  if (logger == null) {
    logger = Logger.getLogger(MyClass.class);
  }
  return logger;
}

这个想法是类可以将调试内容记录到Logger中.需要记录某些内容的第一个代码调用getLogger()并使记录器存在.

关于这种模式,有几件我不喜欢的事情.首先,单例getLogger()不同步并同步它,而正确会无缘无故地给每个后续调用带来负担.

我真的希望能够将其压缩到这样:

private static final Logger logger = Logger.getLogger(MyClass.class);

然后我可以直接引用记录器,甚至不用单独的getter.

我担心的问题是,通过这样做,即使从未调用过记录器,我也会在加载类时创建一个Logger.我有10,000个奇怪的类都调用了getLogger(),所以我实际上在这里创建了多少个Logger实例?如果我的log4j属性包含一些appender,我只是一遍又一遍地引用相同的记录器,或者我是在创建10,000个这样的东西?

解决方法

如果使用认的Log4j配置(即认的LoggerRepository,DefaultCategoryFactory等),那么您将创建10’000个Logger实例.他们消耗了多少内存?除了上帝和你的探查器之外没有人知道这一点. (我的猜测只有后一个会告诉你).

如果内存占用对于您的环境来说太多,请将Logger初始化移动到静态内部类,如下所示:

static class LoggerHolder {
  static Logger logger = Logger.getLogger(MyClass.class);
}

private static Logger getLogger() {
  return LoggerHolder.logger;
}

这样,Logger的实例将仅在第一次getLogger调用时创建. (这种技术称为初始化按需持有者(IODH),它是线程安全的,并且没有同步开销).

我可以给你一个offtopic建议吗?考虑将Log4J替换为SLF4J Logback库的组合.它们是由同一个作者编写的,并描述为“流行的log4j项目的继承者,在log4j离开的地方”.您可以在this SO thread阅读更多内容.

相关文章

最近看了一下学习资料,感觉进制转换其实还是挺有意思的,尤...
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不...
/*list 基本操作 * * List a=new List(); * 增 * a.add(inde...
/* * 内部类 * */ 1 class OutClass{ 2 //定义外部类的成员变...
集合的操作Iterator、Collection、Set和HashSet关系Iterator...
接口中常量的修饰关键字:public,static,final(常量)函数...