Java 同步收集与同步方法?
我有一个类容器,其中包含将由多个线程使用的集合:Java 同步收集与同步方法?,java,multithreading,collections,Java,Multithreading,Collections,我有一个类容器,其中包含将由多个线程使用的集合: public class Container{ private Map<String, String> map; //ctor, other methods reading the map public void doSomeWithMap(String key, String value){ //do some threads safe action map.put(ke
public class Container{
private Map<String, String> map;
//ctor, other methods reading the map
public void doSomeWithMap(String key, String value){
//do some threads safe action
map.put(key, value);
//do something else, also thread safe
}
}
还是使用标准的线程安全装饰器
Collections.synchronizedMap(map);
一般来说,同步地图将保护大多数对地图的访问,而无需进一步考虑。然而,“同步映射”对于迭代是不安全的,这可能是一个问题,取决于您的用例 如果符合您的用例,请考虑使用
如果此对象的其他状态需要防止并发错误,那么如果您在
doSomeWithMap
中执行的其他操作由不同线程同时执行会导致问题(例如,它们更新类级别变量),则需要使用synchronized或锁然后你应该同步整个方法。如果情况并非如此,则应使用同步地图
,以尽量缩短同步锁留在原位的时间 如果您的doSomeWithMap
方法将多次访问映射,您必须同步doSomeWithMap
方法。如果唯一的访问权限是所示的put()
调用,那么最好使用
请注意,“不止一次”是任何调用,迭代器本质上是许多“get”。您可能需要根据需要同步块。请注意这一点
当您使用像ConcurrentHashMap
这样的同步集合或像synchronizedMap()
,synchronizedList()
等这样的集合方法时,只有映射
/列表
是同步的。再进一步解释一下
考虑一下
Map<String, Object> map = new HashMap<>();
Map<String, Object> synchMap = Collections.synchronizedMap(map);
如果要保护地图中的对象,还必须将代码放入同步块中。记住这一点很好,因为在大多数情况下,很多人忘记了保护对象
如果您查看的实现,您将看到它只是一个映射,它包装了一个非线程安全的映射,在调用任何方法之前使用互斥体
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;
}
}
public V get(对象键){
已同步(互斥){return m.get(key);}
}
公共V输入(K键,V值){
已同步(互斥){返回m.put(键,值);}
}
公共集入口集(){
已同步(互斥){
if(entrySet==null)
entrySet=newsynchronizedset(m.entrySet(),互斥);
返回入口集;
}
}
如果您只想保护get
和put
,那么此实现将为您提供保护
但是,如果您想要一个可以由两个或多个线程进行迭代和更新的映射,那么它并不合适,在这种情况下,您应该使用。如果您不需要自己处理并发,那么也不要在此处选中此映射-使用:)@TheLostMind not clear,为什么同步方法是错误的?@St.Antario-这不好,因为您将锁定整个map实例,而在ConcurrentHashMap
中,您将查看效率更高的特定段。因此,两者之间的主要区别是读取的访问不同步,对吗?因此,与concurrentHashMap相比,它给我们带来了性能开销。.@St.AntarioconcurrentHashMap
默认情况下对散列箱组使用单独的锁。这意味着通常更少的锁争用,因为实现可以在没有争用的情况下计算密钥的散列,然后只锁定映射的1/16。ConcurrentHashMap还允许线程安全的迭代。
Object o = synchMap.get("1");// Object referenced by o is not synchronized. Only the map is.
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;
}
}