我有一个包含一个集合的类容器,该集合将由多个线程使用:
synchronized
宣布方法public synchronized void doSomeWithMap(String key, String value)
:
Collections.synchronizedMap(map);
或使用标准的线程安全装饰器?
JSON
答案 0 :(得分:2)
一般来说,同步地图将保护对它的大多数访问,而不必进一步考虑它。但是,“同步映射”对于迭代是不安全的,这可能是一个问题,具体取决于您的用例。 It is imperative that the user manually synchronize on the returned map when iterating over any of its collection views.
如果符合您的使用案例,请考虑使用ConcurrentHashMap。
如果此对象的其他状态需要防止并发错误,那么您将需要使用synchronized或Lock
。
答案 1 :(得分:2)
如果你看一下SynchronizedMap
的实现,你会发现它只是一个包含非线程安全映射的映射,它在调用任何方法之前使用了互斥锁
private void makeButtonsListen(Listener listener) {
for (Button button : aButtons) {
button.addListener(SWT.MouseDown, listener);
}
}
如果你想要的只是保护public V get(Object key) {
synchronized (mutex) {return m.get(key);}
}
public V put(K key, V value) {
synchronized (mutex) {return m.put(key, value);}
}
public Set<Map.Entry<K,V>> entrySet() {
synchronized (mutex) {
if (entrySet==null)
entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
return entrySet;
}
}
和get
,那么这个实现就是为你做的。
但是,如果你想要一个可以迭代并由两个或多个线程更新的Map,那就不合适了,在这种情况下你应该使用ConcurrentHashMap
。
答案 2 :(得分:1)
如果你在doSomeWithMap
内做的其他事情如果由不同的线程同时完成(例如,他们更新类级变量)会导致问题,那么你应该同步整个方法。如果不是这种情况,那么您应该使用同步Map
以最小化同步锁保留的时间长度。
答案 3 :(得分:1)
如果您的doSomeWithMap
方法将多次访问地图 ,则必须同步doSomeWithMap
方法。如果仅访问是显示的put()
调用,则最好使用ConcurrentHashMap。
请注意,“不止一次”是任何调用,而迭代器本质上是很多“获取”。
答案 4 :(得分:1)
您可能应该根据要求同步块。请注意这一点。
当您使用ConcurrentHashMap
等同步收集或synchronizedMap()
,synchronizedList()
等收集方法时,只会同步Map
/ List
。为了进一步解释,
考虑,
Map<String, Object> map = new HashMap<>();
Map<String, Object> synchMap = Collections.synchronizedMap(map);
这使得地图的获取操作是同步的,而不是其中的对象。
Object o = synchMap.get("1");// Object referenced by o is not synchronized. Only the map is.
如果要保护Map内的对象,则还必须将代码放在synchronized块中。这是值得记住的,因为在大多数情况下,许多人忘记了保护对象。
请看这个小信息Collection's synchronizedMap