0

在一个实现中,我编写了以下代码。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] );
    }
  }

当我多次(并非总是)发出并发请求时,它会抛出“java.util.ConcurrentModificationException:并发访问hashmap”错误。我尝试使用

Map<String, String> map= new ConcurrentHashMap<String, String>();
map = iv.getAllValues();

但这并没有解决问题。你能帮帮我,让我知道我在哪里犯了错误。我不能改变的实施

InputVals iv = task.getInputVals();
4

4 回答 4

1

我不完全确定您要实现什么,但正如其他人已经指出的那样,您可能有多个线程试图同时操作返回的映射iv.getAllValues(),因此抛出异常。

使用 a 复制地图ConcurrentHashMap将与处理本地副本一样工作。但是请记住,这样做只会在本地使用它,因此不需要它提供的并发检查。您的代码的问题在于您实际上并未将数据复制到新地图。您将需要执行以下操作:

Map<String, String> map= new ConcurrentHashMap<String, String>( 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] );
    }
  }

除此之外,您需要确保对地图的任何调用都以synchronized块的形式进行。但是,如果您在访问此地图的代码中有几个不同的位置,这可能会非常困难和乏味。

于 2012-10-03T15:17:28.167 回答
0

您必须同步对 getInputVals() 返回的 Map 的所有访问。它正在一个单独的线程中的某个地方进行更改。您将需要以下代码行中的内容,但同样非常重要的是lockObj还必须应用于使用此地图的其他任何地方,包括当前正在修改的任何地方(此代码尚未显示) .

try{
    InputVals iv = task.getInputVals();
    String a;
    String b;

    synchronized (lockOjb) {
        Map<String, String> map = iv.getAllValues();
        a = map.get("value1");
        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] );
    }
  }

这可能会也可能不会,取决于您是否有能力更改此代码。例如,如果它已经在库中发生,您可能只需要重新设计代码,使其不是多线程的,至少在访问此映射的任何地方都是如此。

于 2012-10-03T15:04:06.407 回答
0

你是 做什么的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;
  }
}

我建议你改变如下

Class Inputvals {
  Map<String, String> map = new ConcurrentHashMap<String,String>();
  public void setValue(String a,String b){
    map.put(a,b);
  }
  ..
  ...

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

于 2012-10-04T05:06:01.480 回答
-1

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

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

然后继续访问您的地图。

于 2012-10-03T13:08:22.320 回答