我有一个代码,我试图让我的班级的实例,因为我已经写了一个包装在java.util.logging.Logger
。如何删除check/put的非原子使用并使代码线程安全?
下面的代码片段在我ClientLogger
类 -
private static final Map<Class<?>, ClientLogger> s_classLoggers = new ConcurrentHashMap<Class<?>, ClientLogger>();
final private Logger m_logger;
private ClientLogger(final Class<?> caller) {
m_logger = Logger.getInstance(caller);
}
public static ClientLogger getInstance(final Class<?> klass) {
final ClientLogger result;
if (s_classLoggers.containsKey(klass)) {
result = s_classLoggers.get(klass);
} else {
result = new ClientLogger(klass);
s_classLoggers.put(klass, result);
}
return result;
}
这是我初始化它在我,我需要用我上面记录的其他类的方式 -
private static final ClientLogger s_logger = ClientLogger.getInstance(TestLogger.class);
现在当我运行我的静态分析工具时,它正在抱怨,因为在我的ClientLogger
类中 -
Non-atomic use of check/put on this line s_classLoggers.put(klass, result);
所以我修改了这样上面的代码,使其线程安全 -
private static final ConcurrentHashMap<Class<?>, ClientLogger> s_classLoggers = new ConcurrentHashMap<Class<?>, ClientLogger>();
public static ClientLogger getInstance(final Class<?> klass) {
ClientLogger result;
result = s_classLoggers.putIfAbsent(klass, new ClientLogger(klass));
// is below line thread safe and efficient?
if (result == null) {
result = new ClientLogger(klass);
}
return result;
}
下面是我将初始化它让我的记录器实例的方式 -
private static final ClientLogger s_logger = ClientLogger.getInstance(TestLogger.class);
所以我上面的代码线程安全?我正在做result == null
检查,因为这是第一次,它不会出现在地图中,所以我需要为它创建一个新的值,因此我需要删除结果的最终修饰符。
想想它是否有效。这为每次调用getInstance创建一个ClientLogger,即使不是不存在。也想想它是否有意义。 == null的情况怎么会发生,如果是这样,为什么它有助于用未存储在映射中的局部变量初始化结果? – 2014-09-30 16:35:20
@SimonFischer我认为你是对的,但对于空情况下,它会发生在第一次初始化时,当我试图获取记录器的实例,它是来自null,因为如果它不存在,putIfAbsent将返回null。有没有更好的方法来做到这一点? – john 2014-09-30 16:38:14
你是对的,我正要纠正自己的空情况,第二个答复来了:-)但是,在这种情况下分配结果一个新的ClientLogger实例仍然没有意义,并且没有将它添加到地图中,因为在那种情况下,你正在返回与地图不同的东西。如果地图中没有以前的值,则要将新创建的实例分配给结果。但即使如此,如果存在现有的ClientLogger(),您仍然希望避免创建新的ClientLogger()。 – 2014-09-30 16:44:57