我们有很多类代码,它们有一些如下所示的样板:
private static Logger logger = null;
private static Logger getLogger() {
if (logger == null) {
logger = Logger.getLogger(MyClass.class);
}
return logger;
}
Run Code Online (Sandbox Code Playgroud)
这个想法是类可以将调试内容记录到Logger中.需要记录某些东西的第一个代码调用getLogger()并使记录器存在.
关于这种模式,有几件我不喜欢的事情.首先,单例getLogger()不同步并同步它,而正确会无缘无故地给每个后续调用带来负担.
我真的希望能够将它简化为这样:
private static final Logger logger = Logger.getLogger(MyClass.class);
Run Code Online (Sandbox Code Playgroud)
然后我可以直接引用记录器,甚至不用单独的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;
}
Run Code Online (Sandbox Code Playgroud)
这样, 的实例Logger将仅在第一次调用时创建getLogger。(这种技术称为按需初始化持有者(IODH),它是线程安全的并且具有零同步开销)。
我可以给你一个题外话的建议吗?考虑用SLF4J + Logback库的组合来替换Log4J 。它们是由同一位作者写的,并被描述为“ a successor to the popular log4j project, picking up where log4j leaves off”。您可以在此 SO 线程中阅读更多内容。
| 归档时间: |
|
| 查看次数: |
1657 次 |
| 最近记录: |