Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 同步收集与同步方法?_Java_Multithreading_Collections - Fatal编程技术网

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.Antario
concurrentHashMap
默认情况下对散列箱组使用单独的锁。这意味着通常更少的锁争用,因为实现可以在没有争用的情况下计算密钥的散列,然后只锁定映射的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;
  }
}