0

I am getting a concurrent modification exception when executing the following code:

mymap is a global variable and is a 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());
 }

The exception is thrown by the lines:

resultList.add(future.get());

and

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

However if I try

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

instead the error seems to disappear. Any clues on whats going on?

chapstick
  • 713
  • 6
  • 16
  • 25
  • its a HasHMap()... thank you for pointing that out. – chapstick Jan 31 '14 at 14:55
  • @chapstick u r using multithreading ?? – Kick Jan 31 '14 at 15:10
  • I am not using multi-threading but I was trying to simulate a situation where concurrent execution may happen (given I am in a multi-user env). But I think the issue is all my threads are actually sharing the same instance of mymap(). Although, it doesn't explain why one print statement works and not the other. – chapstick Jan 31 '14 at 15:29
  • Error disappearing on changing a debug message indicate that you have a race condition. – Jakub Zaverka Jan 31 '14 at 16:14

2 Answers2

0

HashMap is not thread safe.

If you want synchronized (i.e. thread-safe) map, use Collections.synchronizedMap() to wrap your HashMap:

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

Or use a ConcurrentHashMap:

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

Jakub Zaverka
  • 8,816
  • 3
  • 32
  • 48
  • Isn't the [concurrent](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentMap.html) collections part of the Collections framework? Are they thread safe? –  Jan 31 '14 at 15:50
  • Incidentally, the [SkipList](http://en.wikipedia.org/wiki/Skip_list) (the backing data structure for the ConcurrentSkipListMap) is my favorite data structure when you sit down and think about how it works and what that implies. –  Jan 31 '14 at 16:05
0

Since there are multiple threads modifying the same instance - you get this error. Regarding,

why one point statement works and not the other

Threads are not guaranteed to provide the same outcome every time. It is possible that if you execute this program many times, you would get different output (no exception, exception at different line etc).

Example - I just executed this program 3 times, execution was successful 2 times and got concurrent exception the third time.

To conclude, one cannot guarantee the order or timing of execution of threads. In order to avoid these errors use synchronization or HashTable which is thread safe - however it comes at cost of performance. Also, having mymap declared as local variable to the method will work - since each thread would have its own copy of local variable - but am assuming that it is an instance variable for a reason.

user1339772
  • 783
  • 5
  • 19