java.util.concurrent.ExecutionException:java.util.ConcurrentModificationException

时间:2014-01-31 14:42:04

标签: java executorservice java.util.concurrent callable

执行以下代码时,我收到并发修改异常:

mymap是一个全局变量,是一个HashMap

 Callable<String> task = new Callable<String>() {
   @Override
   public String call() {           
      mymap.put("myid", "id2");
      mymap.put("myname", "joe");
      String id = mymap.get("myid");
      System.out.println("id is: "+ id+ ", mymap BEFORE: "+mymap.toString());
      mymap.remove("myid");
      System.out.println("id is: "+ id+ ", mymap AFTER: "+mymap.toString());
      return id;
   }
 };

 List<Callable<String>> tasks = Collections.nCopies(7, task);
 ExecutorService executorService = Executors.newFixedThreadPool(7);
 List<Future<String>> futures = executorService.invokeAll(tasks);
 List<String> resultList = new ArrayList<String>(futures.size());

 for (Future<String> future: futures){
    resultList.add(future.get());
 }

行引发异常:

resultList.add(future.get());

System.out.println("id is: "+ id+ ", mymap AFTER: "+mymap.toString()); 

但是,如果我尝试

System.out.println("srcNode AFTER: "+srcNode.toString()+ ", id: "+id);

相反,错误似乎消失了。关于最新情况的任何线索?

2 个答案:

答案 0 :(得分:0)

HashMap不是线程安全的。

如果您想要同步(即线程安全)地图,请使用Collections.synchronizedMap()来包装您的HashMap:

http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#synchronizedMap%28java.util.Map%29

或使用ConcurrentHashMap

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html

答案 1 :(得分:0)

由于有多个线程修改同一个实例 - 您会收到此错误。关于,

  

为什么一个点语句有效而另一个

不保证线程每次都提供相同的结果。如果你多次执行这个程序,你可能得到不同的输出(没有异常,不同行的异常等)。

示例 - 我刚刚执行了3次这个程序,执行成功了2次,并且第三次得到并发异常。

总而言之,我们无法保证线程执行的顺序或时间。为了避免这些错误,使用同步或HashTable是线程安全的 - 但是它会以性能为代价。此外,将mymap声明为方法的局部变量也可以 - 因为每个线程都有自己的局部变量副本 - 但我假设它是一个实例变量,原因就在这里。