java.util.ConcurrentModificationException:对hashmap的并发访问

java.util.ConcurrentModificationException:对hashmap的并发访问,java,concurrency,map,hashmap,Java,Concurrency,Map,Hashmap,在一个实现中,我编写了以下代码。try-catch块位于方法中 try{ InputVals iv = task.getInputVals(); Map<String, String> map = iv.getAllValues(); String a = map.get("value1"); String b = map.get("value2"); String x = funcxy.methodGetX(); String y =

在一个实现中,我编写了以下代码。try-catch块位于方法中

try{
    InputVals iv = task.getInputVals();
    Map<String, String> map = iv.getAllValues();
    String a = map.get("value1");
    String b = map.get("value2");
    String x = funcxy.methodGetX();
    String y = funcxy.methodGetY();
    iv.setValue(xval, x);
    iv.setValue(yval,y);

    String []names = {"name1", "name2", "name3"}
    for(int i = 0; i<names.length; i++ ){
         iv.setValue("name"+i, names[i] );
    }
  }

您可能需要将地图包装到同步集合中

Map<String, String> map = Collections.synchronizedMap(iv.getAllValues());
Map-Map=Collections.synchronizedMap(iv.getAllValues());

然后继续访问地图。

您必须同步对getInputVals()返回的地图的所有访问。它在一个单独的线程中的某个地方被修改。您需要按照下面的代码进行操作,但同样重要的是,lockObj也必须应用于使用此地图的任何其他地方,包括当前正在修改的地方(此代码尚未显示)

试试看{
InputVals iv=task.getInputVals();
字符串a;
b串;
已同步(lockOjb){
Map Map=iv.getAllValues();
a=映射获取(“值1”);
b=映射获取(“值2”);
}
字符串x=funcxy.methodGetX();
字符串y=funcxy.methodGetY();
iv.设定值(xval,x);
iv.设定值(yval,y);
字符串[]名称={“name1”、“name2”、“name3”}

对于(int i=0;i我不完全确定您试图实现什么,但正如其他人已经指出的,您可能有多个线程试图同时操作由
iv.getAllValues()
返回的映射,因此引发异常


使用
ConcurrentHashMap
复制映射的工作方式与使用本地副本的工作方式相同。但是请记住,这样做时,您将仅在本地使用映射,因此不需要它提供的并发性检查。代码的问题是,您实际上没有将数据复制到新映射。您将d必须做到:

Map<String, String> map= new ConcurrentHashMap<String, String>( iv.getAllValues() );
Map Map=newconcurrenthashmap(iv.getAllValues());
根据您在修改映射条目时的需要,最简单和最快的方法可能是复制映射并使用本地副本。这将防止任何并发问题。当然,如果其他线程需要访问您的更新信息,则此计划不起作用

try{
    InputVals iv = task.getInputVals();
    Map<String, String> map = new HashMap<String, String>();
    // copy all map values to a local var
    map.putAll( iv.getAllValues() );
    String a = map.get("value1");
    String b = map.get("value2");
    String x = funcxy.methodGetX();
    String y = funcxy.methodGetY();
    iv.setValue(xval, x);
    iv.setValue(yval,y);

    String []names = {"name1", "name2", "name3"}
    for(int i = 0; i<names.length; i++ ){
         iv.setValue("name"+i, names[i] );
    }
  }
试试看{
InputVals iv=task.getInputVals();
Map Map=newhashmap();
//将所有映射值复制到本地变量
map.putAll(iv.getAllValues());
字符串a=map.get(“value1”);
字符串b=map.get(“value2”);
字符串x=funcxy.methodGetX();
字符串y=funcxy.methodGetY();
iv.设定值(xval,x);
iv.设定值(yval,y);
字符串[]名称={“name1”、“name2”、“name3”}

对于(int i=0;i您的
InputVals.setValue()
做什么?它是如何定义的?如果您在使用原始变量的引用时在业务逻辑中定义ConcurrentHashMap,则没有任何用处。您需要注意实际的bean本身

如果它是像下面这样的东西

Class Inputvals {
  Map<String, String> map = new HashMap <String,String>();
  public void setValue(String a,String b){
    map.put(a,b);
  }
  public Map<String,String> getAllValues(){
    return map;
  }
}
类输入{
Map Map=newhashmap();
public void setValue(字符串a、字符串b){
地图放置(a,b);
}
公共映射getAllValues(){
返回图;
}
}
我建议你改变如下

Class Inputvals {
  Map<String, String> map = new ConcurrentHashMap<String,String>();
  public void setValue(String a,String b){
    map.put(a,b);
  }
  ..
  ...
类输入{
Map Map=新的ConcurrentHashMap();
public void setValue(字符串a、字符串b){
地图放置(a,b);
}
..
...

这可以帮助您解决多线程访问问题。

是for for循环中的代码吗?您可能会考虑发布更多代码。我道歉。我已经用更多代码更新了查询。首先,显示实际的StActTrac迹。第二,您说您正在执行并发请求,您是否表示所显示的代码处于方法BEIN中?g在多个线程上并发调用?是的,显示的代码是一种方法。您需要显示更多的代码,因为在显示的代码中不可能获得异常。您没有显示映射的实际修改位置。只有两个get。这将使每个线程包装映射,因此它们将uld不会阻止彼此访问基础映射。它仍将被并发访问。
ConcurrentHashMap
不是包装器。它是一个实际的并发hashmap实现。@MarkoTopolnik同意-我的错误;我正在考虑集合。synchronizedMap()。我编辑了我的回复以反映这一点。这是我的观点:
InputVals
是OP控制下的一个类。他应该进入其实现,并将用于保存InputVals的映射实现更改为
ConcurrentHashMap
。也许您可以建议(如果您同意的话)@MarkoTopolnik绝对正确,但有两件事需要记住。1)OP表示他无法更改
InputVals iv=task.getInputVals();
2)的实现仅仅将其更改为ConcurrentHashMap并不一定能解决所有问题。仍然可能会有意外的副作用。ConcurrentHashMap提供的只是一个保证,即没有线程会同时更改映射的值。但是,它不能保证两个线程不会在一个线程的值覆盖另一个。我设法错过了问题中的最后一句话,是的。但是,关于竞争条件,不可能知道这是否是一个实际问题。为了记录在案,CHM实际上允许两个线程同时更改映射(这是一个真正的并发映射实现,而不仅仅是线程安全的)。
try{
    InputVals iv = task.getInputVals();
    Map<String, String> map = new HashMap<String, String>();
    // copy all map values to a local var
    map.putAll( iv.getAllValues() );
    String a = map.get("value1");
    String b = map.get("value2");
    String x = funcxy.methodGetX();
    String y = funcxy.methodGetY();
    iv.setValue(xval, x);
    iv.setValue(yval,y);

    String []names = {"name1", "name2", "name3"}
    for(int i = 0; i<names.length; i++ ){
         iv.setValue("name"+i, names[i] );
    }
  }
Class Inputvals {
  Map<String, String> map = new HashMap <String,String>();
  public void setValue(String a,String b){
    map.put(a,b);
  }
  public Map<String,String> getAllValues(){
    return map;
  }
}
Class Inputvals {
  Map<String, String> map = new ConcurrentHashMap<String,String>();
  public void setValue(String a,String b){
    map.put(a,b);
  }
  ..
  ...