4

我在 luaj 中找到了以下代码片段,我开始怀疑是否有可能Map在构建之后对它所做的更改可能对其他线程不可见,因为没有同步到位。

我知道,由于Map被声明为 final,它在构造后的初始化值对其他线程是可见的,但是在那之后发生的变化呢?

有些人可能还意识到这个类不是线程安全的,以至于在多线程环境中调用 coerce 甚至可能导致HashMap.

public class CoerceJavaToLua {
    static final Map COERCIONS = new HashMap(); // this map is visible to all threads after construction, since its final

    public static LuaValue coerce(Object paramObject) {
        ...;
        if (localCoercion == null) {
            localCoercion = ...;
            COERCIONS.put(localClass, localCoercion); // visible?
        }
        return ...;
    }

    ...
}
4

3 回答 3

3

您是正确的,Map其他线程可能看不到对 的更改。访问(读取和写入)的每个方法COERCIONS都应该synchronized在同一个对象上。或者,如果您从不需要原子访问序列,则可以使用同步集合

(顺便说一句,你为什么使用原始类型?)

于 2015-08-25T03:39:32.183 回答
2

这段代码实际上很糟糕,可能会导致很多问题(可能不是无限循环,这在 中更常见TreeMapHashMap因为覆盖或可能是一些随机异常更可能导致无声数据丢失)。你是对的,不能保证在一个线程中所做的更改会被另一个线程看到。

这里的问题可能看起来不是很大,因为它Map用于缓存目的,因此静默覆盖或可见性滞后不会导致真正的问题(只有两个不同的强制实例将用于同一个类,这可能在这个案子)。但是,这样的代码仍然有可能会破坏您的程序。如果您愿意,可以向 LuaJ 团队提交补丁。

于 2015-08-25T03:50:47.463 回答
0

两种选择:

// Synchronized (since Java 1.2)
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());

// Concurrent (since Java 5)
static final Map COERCIONS = new ConcurrentHashMap();

他们每个人都有自己的优点和缺点。

ConcurrentHashMappro是没有锁的。缺点是操作不是原子的,例如Iterator一个线程中的一个线程和另一个线程中的调用putAll将允许迭代器看到一些添加的值。

于 2015-08-25T03:47:41.513 回答