静态分析期间非原子使用检查/放置错误

时间:2014-09-30 00:41:21

标签: java multithreading atomic

我有一个代码,我试图获取我的类的实例,因为我已经编写了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;
}

2 个答案:

答案 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将被放入映射中。)