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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.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_Synchronization_Synchronized - Fatal编程技术网

Java映射同步

Java映射同步,java,multithreading,synchronization,synchronized,Java,Multithreading,Synchronization,Synchronized,我正在做一件我定义了Collections.synchronizedMap的事情 在一个线程A中,它将只获取值,并放入一个更新的值,这样就不会出现问题 在另一个线程B中,它将遍历条目,然后根据条目的值进行比较,如果它符合某些条件,它将从映射中删除该条目 我的理解是,同步地图将阻止访问 但是有没有可能线程B获取一个条目,然后线程A更新该值,然后线程B删除该值,因为它符合某些条件,但它不应该有,因为线程A将其更新为的值。解决这个问题的最佳实现是什么?听起来您只需要同步“获取、检查和删除”部分。例如:

我正在做一件我定义了Collections.synchronizedMap的事情

在一个线程A中,它将只获取值,并放入一个更新的值,这样就不会出现问题

在另一个线程B中,它将遍历条目,然后根据条目的值进行比较,如果它符合某些条件,它将从映射中删除该条目

我的理解是,同步地图将阻止访问


但是有没有可能线程B获取一个条目,然后线程A更新该值,然后线程B删除该值,因为它符合某些条件,但它不应该有,因为线程A将其更新为的值。解决这个问题的最佳实现是什么?

听起来您只需要同步“获取、检查和删除”部分。例如:

Iterable<String> keys;
synchronized (map) {
    keys = new ArrayList<>(map.keySet());
}
for (String key : keys) {
    synchronized (map) {
        Integer value = map.get(key);
        // The other thread won't be able to update the value at this point
        if (value != null && value < 0) {
            map.remove(key);
        }
    }
}
Iterable键;
同步(地图){
keys=newarraylist(map.keySet());
}
用于(字符串键:键){
同步(地图){
整数值=map.get(键);
//另一个线程此时将无法更新该值
如果(值!=null&&value<0){
地图。删除(键);
}
}
}

您的更新线程可能需要做同样的事情-从您的描述中不清楚它是否需要“查看”删除。

听起来您只需要同步“获取、检查和删除”部分。例如:

Iterable<String> keys;
synchronized (map) {
    keys = new ArrayList<>(map.keySet());
}
for (String key : keys) {
    synchronized (map) {
        Integer value = map.get(key);
        // The other thread won't be able to update the value at this point
        if (value != null && value < 0) {
            map.remove(key);
        }
    }
}
Iterable键;
同步(地图){
keys=newarraylist(map.keySet());
}
用于(字符串键:键){
同步(地图){
整数值=map.get(键);
//另一个线程此时将无法更新该值
如果(值!=null&&value<0){
地图。删除(键);
}
}
}

您的更新线程可能需要做同样的事情-从您的描述中不清楚是否需要“查看”删除。

您还需要同步正在使用映射的代码块

请看这里:

您还需要同步正在使用映射的代码块

请看这里:

听起来您好像在尝试实现缓存。有很多好的并发缓存实现。我相信它有一个相当不错的实现。

听起来你在尝试实现缓存。有很多好的并发缓存实现。我相信它有一个相当不错的实现。

这可以完全不用像这样使用

final ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(); // creation
map.put("aKey", "aValue"); // example content

// Thread A:
map.replace("aKey", "aNewValue"); // atomic replace call

// Thread B:
for (String key : map.keySet()) {
  do {
    processed = true;
    final String value = map.get(key);
    if ((value != null) && shouldRemove(value)) { // some comparison or check
      if (map.remove("aKey", value) == false) { // is value still the same?
        processed = false; // value has been changed in between, try again
      }
    }
  } while (processed == false);
}
final ConcurrentHashMap=new ConcurrentHashMap();//创造
map.put(“aKey”、“aValue”);//示例内容
//线程A:
映射。替换(“aKey”、“aNewValue”);//原子替换调用
//线程B:
for(字符串键:map.keySet()){
做{
已处理=真;
最终字符串值=map.get(键);
如果((value!=null)&&shouldRemove(value)){//进行一些比较或检查
如果(map.remove(“aKey”,value)==false){//值是否仍然相同?
processed=false;//值在这段时间内已更改,请重试
}
}
}while(processed==false);
}
这是线程安全的,因为线程B只会删除值(原子性地),如果在这两个值之间没有更改的话。如果在这两个值之间发生了更改,线程B将重试并使用新值进行比较。这与其他原子类中使用的
compareAndSet
的概念类似


如果线程A很少更改,那么线程B将以与未同步映射几乎相同的速度执行。如果线程A做了很多更改,那么线程B中可能会有几个重复调用,这取决于执行比较所需的时间以及值更改的频率。但在所有情况下,这都是线程安全的,比任何同步实现都要快。

这完全可以在不阻塞的情况下完成,使用如下方法:

final ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(); // creation
map.put("aKey", "aValue"); // example content

// Thread A:
map.replace("aKey", "aNewValue"); // atomic replace call

// Thread B:
for (String key : map.keySet()) {
  do {
    processed = true;
    final String value = map.get(key);
    if ((value != null) && shouldRemove(value)) { // some comparison or check
      if (map.remove("aKey", value) == false) { // is value still the same?
        processed = false; // value has been changed in between, try again
      }
    }
  } while (processed == false);
}
final ConcurrentHashMap=new ConcurrentHashMap();//创造
map.put(“aKey”、“aValue”);//示例内容
//线程A:
映射。替换(“aKey”、“aNewValue”);//原子替换调用
//线程B:
for(字符串键:map.keySet()){
做{
已处理=真;
最终字符串值=map.get(键);
如果((value!=null)&&shouldRemove(value)){//进行一些比较或检查
如果(map.remove(“aKey”,value)==false){//值是否仍然相同?
processed=false;//值在这段时间内已更改,请重试
}
}
}while(processed==false);
}
这是线程安全的,因为线程B只会删除值(原子性地),如果在这两个值之间没有更改的话。如果在这两个值之间发生了更改,线程B将重试并使用新值进行比较。这与其他原子类中使用的
compareAndSet
的概念类似


如果线程A很少更改,那么线程B将以与未同步映射几乎相同的速度执行。如果线程A做了很多更改,那么线程B中可能会有几个重复调用,这取决于执行比较所需的时间以及值更改的频率。但在所有情况下,这都是线程安全的,比任何同步实现都要快。

首先介绍解决方案。我认为最好的解决方案是标准的ConcurrentHashMap。它具有如下移除的CAS操作:

boolean remove(Object key, Object value)
Removes the entry for a key only if currently mapped to a given value.
希望能有帮助

现在,第二件事是关于“我的理解是,同步映射将阻止访问。”我认为这不是完全的理解,请参见以下同步映射javadoc的详细信息:

* It is imperative that the user manually synchronize on the returned
 * map when iterating over any of its collection views:
 * <pre>
 *  Map m = Collections.synchronizedMap(new HashMap());
 *      ...
 *  Set s = m.keySet();  // Needn't be in synchronized block
 *      ...
 *  synchronized (m) {  // Synchronizing on m, not s!
 *      Iterator i = s.iterator(); // Must be in synchronized block
 *      while (i.hasNext())
 *          foo(i.next());
 *  }
 * </pre>
*用户必须手动同步返回的
*在其任何集合视图上迭代时映射:
* 
*Map m=Collections.synchronizedMap(新的HashMap());
*      ...
*设置s=m.keySet();//不必在同步块中
*      ...
*已同步(m){//在m上同步,而不是在s上同步!
*迭代器i=s.Iterator();//必须在同步块中
*while(i.hasNext())
*foo(i.next());
*  }
*