1

我正在考虑EnumMap在并发环境中使用。但是,环境是非典型的,原因如下:

  • EnumMap总是满的:当映射暴露给并发环境时,没有未映射的键
  • 仅使用put()andget()操作(不迭代、不等remove()
  • 如果调用get()不反映put()立即或有序调用是完全可以接受的。

从我收集到的信息(包括相关方法源代码)来看,这似乎是一个安全的场景(与允许迭代不同)。有什么我可能忽略的吗?

4

3 回答 3

4

直接来自JavaDoc

像大多数集合实现一样,EnumMap 是不同步的。如果多个线程同时访问一个枚举映射,并且至少有一个线程修改了映射,则应该在外部进行同步。这通常是通过同步一些自然封装枚举映射的对象来完成的。如果不存在这样的对象,则应使用该Collections.synchronizedMap(java.util.Map<K, V>)方法“包装”地图。这最好在创建时完成,以防止意外的不同步访问:

 Map<EnumKey, V> m = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));
于 2014-01-21T11:44:46.947 回答
4

一般来说,跨线程使用非线程安全的类会带来很多问题。在您的特定情况下,假设在所有键都分配了值之后安全发布(例如),我从Java 1.6 中的代码map.size() == TheEnum.values().length的快速浏览中可以看到的唯一问题是 a可能永远不会反映在另一个线程中。但这只是因为's 实现的内部结构,这在未来可能会发生变化。换句话说,未来的变化可能会以更危险、更微妙的方式破坏用例。EnumMapputEnumMap

编写仍然包含数据竞争的正确代码是可能的——但这很棘手。为什么不将实例包装在 a 中Collections.synchronizedMap

于 2014-01-21T11:46:24.163 回答
1

您遇到的问题是线程可能永远不会看到另一个线程所做的更改,或者他们可能会看到部分更改。这与在 java 5 引入 volatile 之前双重检查锁定被破坏的原因相同。

如果您将 EnumMap 引用设置为易失性,它可能会起作用,但即使那样我也不是 100% 确定,您可能需要 EnumMap 内部的内部引用是易失性的,显然如果不使用您自己的 EnumMap 版本,您将无法做到这一点。

于 2014-01-21T11:46:14.873 回答