我有一个代码,我试图获取我的类的实例,因为我已经编写了java.util.logging.Logger
的包装器。
以下是我的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);
现在,当我运行静态分析工具时,它正在抱怨 -
Non-atomic use of check/put on this line s_classLoggers.put(klass, result);
在ClientLogger
课程中我不知道为什么?我在这里做错了什么?
更新: -
这是我更新的代码 -
private static final ConcurrentHashMap<Class<?>, ClientLogger> s_classLoggers = new ConcurrentHashMap<Class<?>, ClientLogger>();
public static ClientLogger getInstance(final Class<?> klass) {
final ClientLogger result;
result = new ClientLogger(klass);
s_classLoggers.putIfAbsent(klass, result);
return 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));
if (result == null) {
result = new ClientLogger(klass);
}
return result;
}
答案 0 :(得分:2)
您的代码不是线程安全的,因为不同的线程可能会在第一个线程上的两个调用之间调用put()
。
相反,您应该致电putIfAbsent()
。
答案 1 :(得分:1)
你正在测试
s_classLoggers.containsKey(klass)
在一行代码上。几行之后你输入一个值
s_classLoggers.put(klass, result);
当然,另一个线程可能同时更新了哈希映射。在多线程中,您不能在一行上进行测试,然后在另一行上有条件地操作,因为条件可能是错误的。同样,get
一行后来可能会返回null,因为另一个线程可能已经删除了之前有一行的条目。
原子操作,其中测试和更新在单个操作中完成:
newLogger = new ClientLogger(klass);
result = s_classLoggers.putIfAbsent(klass, newLogger);
if (result == null) {
result = newLogger;
}
(更改了上面的代码,以便结果始终是映射的值,因为如果之前没有映射任何内容,putIfAbsent将返回null,并且在这种情况下,newLogger将被放入映射中。)