我有一个代码,我试图获取我的类的实例,因为我已经编写了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);
现在,当我运行静态分析工具时,它正在我的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
检查,因为这是第一次,它不会出现在地图中,所以我需要为它创建一个新值,因此,我需要删除结果的最终修饰符
答案 0 :(得分:3)
您需要的是Java 8的
s_classLoggers.computeIfAbsent(klass, ClientLogger::new);
这只会在必要时创建对象。
注意,ClientLogger::new
是一个惊人的短手,因为它是k -> new ClientLogger(k)
的缩写,是
new Function<Class<?>, ClientLogger>() {
public ClientLogger apply(Class<?> k) {
return new ClientLogger(k);
}
}
并且lambda甚至在编译时都不生成类,尽管JVM可以(并且在Java 8中)在运行时创建一个类。
否则你可能会发现使用写锁更安全。
public static ClientLogger getInstance(final Class<?> klass) {
ClientLogger result = s_classLoggers.get(klass);
if (result != null)
return result; // fast path
// slow, but rare path
synchronized (s_classLoggers) {
result = s_classLoggers.get(klass);
if (result == null)
s_classLoggers.put(klass, result = new ClientLogger(klass));
}
return result;
}