我正在考虑EnumMap
在并发环境中使用。但是,环境是非典型的,原因如下:
EnumMap
总是满的:当映射暴露给并发环境时,没有未映射的键- 仅使用
put()
andget()
操作(不迭代、不等remove()
) - 如果调用
get()
不反映put()
立即或有序调用是完全可以接受的。
从我收集到的信息(包括相关方法源代码)来看,这似乎是一个安全的场景(与允许迭代不同)。有什么我可能忽略的吗?
我正在考虑EnumMap
在并发环境中使用。但是,环境是非典型的,原因如下:
EnumMap
总是满的:当映射暴露给并发环境时,没有未映射的键put()
andget()
操作(不迭代、不等remove()
)get()
不反映put()
立即或有序调用是完全可以接受的。从我收集到的信息(包括相关方法源代码)来看,这似乎是一个安全的场景(与允许迭代不同)。有什么我可能忽略的吗?
直接来自JavaDoc:
像大多数集合实现一样,EnumMap 是不同步的。如果多个线程同时访问一个枚举映射,并且至少有一个线程修改了映射,则应该在外部进行同步。这通常是通过同步一些自然封装枚举映射的对象来完成的。如果不存在这样的对象,则应使用该
Collections.synchronizedMap(java.util.Map<K, V>)
方法“包装”地图。这最好在创建时完成,以防止意外的不同步访问:
Map<EnumKey, V> m = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));
一般来说,跨线程使用非线程安全的类会带来很多问题。在您的特定情况下,假设在所有键都分配了值之后安全发布(例如),我从Java 1.6 中的代码map.size() == TheEnum.values().length
的快速浏览中可以看到的唯一问题是 a可能永远不会反映在另一个线程中。但这只是因为's 实现的内部结构,这在未来可能会发生变化。换句话说,未来的变化可能会以更危险、更微妙的方式破坏用例。EnumMap
put
EnumMap
编写仍然包含数据竞争的正确代码是可能的——但这很棘手。为什么不将实例包装在 a 中Collections.synchronizedMap
?
您遇到的问题是线程可能永远不会看到另一个线程所做的更改,或者他们可能会看到部分更改。这与在 java 5 引入 volatile 之前双重检查锁定被破坏的原因相同。
如果您将 EnumMap 引用设置为易失性,它可能会起作用,但即使那样我也不是 100% 确定,您可能需要 EnumMap 内部的内部引用是易失性的,显然如果不使用您自己的 EnumMap 版本,您将无法做到这一点。