最近發現項目中的日志用得不大規范,于是準備做些改造,在我們項目中用的是 slf4j1.5.10 的版本,順便看了下 slf4j 的源碼,看到 LoggerFactory 初始化的邏輯如下
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITILIZATION;
performInitialization();
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITILIZATION:
return getSingleton().getLoggerFactory();
case FAILED_INITILIZATION:
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITILIZATION:
// support re-entrant behavior.
// See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
return TEMP_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
有發現什么問題嗎?再看看 INITIALIZATION_STATE 這個變量是怎么聲明的,如下
static int INITIALIZATION_STATE = UNINITIALIZED;
現在很明確了,如果在多線程環境下,多個線程調用 LoggerFactory.getLogger() 方法的時候初始化會出現問題,這簡直有點顛覆世界觀,說好的大神代碼呢?懷著極度懷疑自己的心情翻看了最新的 slf4j1.7.21 代碼,看到初始化邏輯如下:
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
performInitialization();
}
}
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case NOP_FALLBACK_INITIALIZATION:
return NOP_FALLBACK_FACTORY;
case FAILED_INITIALIZATION:
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITIALIZATION:
// support re-entrant behavior.
// See also http://jira.qos.ch/browse/SLF4J-97
return SUBST_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
再看看 INITIALIZATION_STATE 變量的聲明
static volatile int INITIALIZATION_STATE = UNINITIALIZED;
頓時淚流滿面,這才像傳說中的大神代碼啊