静态初始化unmodifiableCollection.get保证不可变吗?
有关:
静态最终地图FOO = Collections.unmodifiableMap(new HashMap());
多个线程可以使用方法获取而不会遇到问题吗?
即使FOO中的项目无法添加/删除,什么阻止get方法操纵FOO的内部状态以进行缓存等。如果内部状态以任何方式被修改,则FOO不能同时使用。如果是这种情况,java中真正的不可变集合在哪里?
答案 0 :(得分:4)
给出具体的例子:
static final Map FOO = Collections.unmodifiableMap(new HashMap());
然后FOO将是不可变的。它也永远不会有任何元素。鉴于更一般的情况:
static final Map BAR = Collections.unmodifiableMap(getMap());
然后,这是否是不可变的完全取决于其他人是否可以到达底层地图,以及它是什么类型的地图。例如,如果它是LinkedHashMap,则可以通过访问顺序修改基础链接列表,并且可以通过调用get()来更改。最安全的方法(使用非并发类)可以:
static final Map BAR = Collections.unmodifiableMap(new HashMap(getMap()));
javadocs for HashMap暗示只要你不对地图进行任何结构改变,那么同时使用它是安全的,所以对于你可以使用的任何访问器来说这应该是安全的,即各种集合并迭代它们和get()应该是安全的。
如果您可以使用并发类,那么您也可以这样做:
static final Map BAR = Collections.unmodifiableMap(new ConcurrentHashMap(getMap());
这将明确安全地从多个线程使用,因为ConcurrentHashMap显然是多线程访问安全的。内部状态可能是可变的,但外部可见状态不会,并且因为类保证是线程安全的,所以我们可以安全地认为它是外部不可变的。
答案 1 :(得分:2)
冒着听起来像我正在广告狂欢的风险,请使用Google Immutable Collections并完成它。
答案 2 :(得分:0)
Java SDK中没有真正的不可变映射。所有建议的Chris地图都只是线程安全的。不可修改的Map也不是不可变的,因为如果基础Map发生了变化,那么ConcurrentModificationException
也会出现。{/ p>
如果您想要真正不可变的地图,请使用Google Collections / Guava中的ImmutableMap。
答案 3 :(得分:0)
其实是个好问题。想想WeakHashMap
- 可以在没有调用变异操作的情况下进行更改。访问顺序模式中的LinkedHashMap
大致相同。
HashMap
州的API文档:
请注意,此实现不是 synchronized。如果有多个线程 同时访问哈希映射,并在 至少有一个线程修改了 在结构上映射,它必须是 外部同步。 (结构性的 修改是任何操作 添加或删除一个或多个映射; 只是改变相关的价值 用一个实例已经的密钥 包含不是结构 修改。)
据推测,那应该是当且仅当。这意味着如果get
“实际上是不可变的”,则HashMap
不需要同步。
答案 4 :(得分:-1)
我建议任何线程操作使用ConcurrentHashMap或HashTable,两者都是线程安全的。
答案 5 :(得分:-1)
只要对象遵守其合同(即无法修改的地图),返回的地图上的吸气剂是否恰好与某种内部状态混合是不重要的。所以你的问题是“咆哮错误的树”。
如果您对所包含的地图没有所有权和控制权,那么您对UnmodifiableMap持谨慎态度是正确的。例如
Map<String,String> wrapped = new HashMap<String,String>();
wrapped.add("pig","oink");
Map<String,String> wrapper = Collections.unmodifiableMap(wrapped);
System.out.println(wrapper.size());
wrapper.put("cow", "moo"); // throws exception
wrapped.put("cow", "moo");
System.out.println(wrapper.size()); // d'oh!