如果我静态初始化地图并将引用设置为Collections.unmodifiableMap(Map m)。我是否需要同步读取?
private static final Map<String,String> staticMap;
static{
Map<String,String> tempMap = new HashMap<String,String>();
tempMap.put("key 1","value 1");
tempMap.put("key 2","value 2");
tempMap.put("key 3","value 3");
staticMap = Collections.unmodifiableMap(tempMap);
}
答案 0 :(得分:10)
不,您在那里创建的地图实际上是不可变的(因为没有任何引用可变支持地图)并且对并发访问是安全的。如果您想更清楚地保证这一点,并且更容易创建地图,Guava的ImmutableMap类型就是为了这种用途而设计的(除此之外):
private static final ImmutableMap<String, String> staticMap = ImmutableMap.of(
"key1", "value1",
"key2", "value2",
"key3", "value3");
答案 1 :(得分:5)
不,读取不要修改地图,所以我根本不用担心。它只是写+写或写+读取,需要围绕它进行同步。
答案 2 :(得分:4)
这取决于Map的实现。 HashMap,TreeMap等都具有免费修改的读取,因此很好,但跟踪使用情况的实现可能会在内部执行更新。
一个例子是具有访问顺序的LinkedHashMap:
new LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)
这实际上会对每次读取时的元素进行重新排序,以便对键,值或条目的迭代将在最后一次访问的第一个顺序中进行。另一个可能修改的地图是WeakHashMap
。
一个很好的替代方案是Google的番石榴库中的ImmutableMap
。
答案 3 :(得分:4)
我不同意上述答案。地图实现中包含的是非易失性字段(如HashMap.entrySet
。在不可修改的情况下:UnmodifiableMap.keySet
,UnmodifiableMap.entrySet
和UnmodifiableMap.values
)。这些字段被懒惰地初始化,因此在静态初始化器之后为NULL。如果一个线程然后调用entrySet()
,则初始化entrySet字段。从所有其他线程访问此字段是不安全的。可以从处于不一致状态的另一个线程看到该字段,或者根本不看到该字段。
答案 4 :(得分:3)
简短的回答是:不。如果没有读写争用,则无需锁定。只有当你共享的内容可能发生变化时才会锁定,如果它没有改变,那么它基本上是不可变的,并且不可变的被认为是线程安全的。
答案 5 :(得分:1)
我认为其他人已经覆盖了答案(在HashMap实现的情况下是的)。如果您不一定总是需要创建地图,可以使用Initialize-On-Demand Holder惯用法使其变得懒惰:
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class YourClass {
// created only if needed, thread-safety still preserved
private static final class MapHolder {
private static final Map<String,String> staticMap;
static{
System.out.println("Constructing staticMap");
Map<String,String> tempMap = new HashMap<String,String>();
tempMap.put("key 1","value 1");
tempMap.put("key 2","value 2");
tempMap.put("key 3","value 3");
staticMap = Collections.unmodifiableMap(tempMap);
}
}
// use this to actually access the instance
public static Map<String,String> mapGetter() {
return MapHolder.staticMap;
}
public static void main(String[] arg) {
System.out.println("Started, note that staticMap not yet created until...");
Map<String,String> m = mapGetter();
System.out.println("we get it: " + m);
}
}
将打印:
Started, note that staticMap not yet created until...
Constructing staticMap
we get it: {key 1=value 1, key 2=value 2, key 3=value 3}