4 Replies Latest reply: Feb 3, 2012 8:09 AM by 796440 RSS

    Multithreading - Concurrent modification exception

    913819
      I am using multithreads. I have two classes.

      1. FirstClass.java
      In this class i just simply iterate through a collection without modifying it.

      2. SecondClass.java
      In this class the collection is created and modified


      FirstClass.java
          public Set findExceptions(long id, Set rules, SecondClass mapC)
          {
               
               Set result = new HashSet();
               Set<Rule> existingRules = new HashSet(rules);
               Set allExceptions = mapC.findValidationExceptionsByMapObject(id); //this calls the below method in SecondClass.java
               Iterator exceptionIter = allExceptions.iterator();
               while (exceptionIter.hasNext()) {
                  ValidationException valException = (ValidationException) exceptionIter.next();  //I get java exception here
                   Rule rule = valException.rule();
      
                   for (Rule existingRule : existingRules) {
                       if (existingRule.ruleCode().equals(rule.ruleCode())) {
                            result.add(valException);
                       }
                   }
               }
      
               return result;
          }
      SecondClass.java
           //declare the collection
           private final Map<Long, Set<ValidationException>> d_validationExceptionsByMapObject = new HashMap<Long,
              Set<ValidationException>>();
                      
      
          public Set<ValidationException> findValidationExceptionsByMapObject(long mapObjectId)
          {
              Set<ValidationException> result;
      
              if (d_validationExceptionsByMapObject.containsKey(mapObjectId))
              {
                  result = Collections.unmodifiableSet(d_validationExceptionsByMapObject.get(mapObjectId));
              }
              else
              {
                  result = Collections.<ValidationException>emptySet();
              }
      
              return result;
          }
      
          public  void indexValidationException(ValidationException exception, long id)
          {
                      d_validationExceptionsByMapObject.put(id, exception);
          }
      The exception is occurring because while one thread is iterating through collection in findExceptions method, another thread is writing to the same collection(d_validationExceptionsByMapObject) in the SecondClass().  Can you suggest something ?

      I am attaching the exception log
      SEVERE: Error executing rules in thread
      java.util.concurrent.ExecutionException: java.util.ConcurrentModificationException
           at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
           at java.util.concurrent.FutureTask.get(FutureTask.java:83)
           at com.navtech.val.service.MultiThreadedDeltaValidationService.runDeltaValidationsInternal(MultiThreadedDeltaValidationService.java:134)
           at com.navtech.val.service.MultiThreadedDeltaValidationService.executeDeltaValidationsUsingThreads(MultiThreadedDeltaValidationService.java:89)
           at com.navtech.val.ValidationServiceImpl.getDeltaValidationResults(ValidationServiceImpl.java:2250)
           at com.navtech.val.ValidationServiceImpl.runDeltaValidations(ValidationServiceImpl.java:2215)
           at com.navtech.val.ValidationServiceImpl.validate(ValidationServiceImpl.java:2134)
           at com.navtech.bison.ui.common.mapmodel.MapModel.reindex(MapModel.java:3018)
           at com.navtech.bison.ui.common.mapmodel.MapModel.execute(MapModel.java:2652)
           at com.navtech.bison.ui.common.mapmodel.MapModel.execute(MapModel.java:2587)
           at com.navtech.atlas.NavLinkUpdateCommand.apply(NavLinkUpdateCommand.java:5739)
           at com.navtech.atlas.NavLinkViewController.applyButtonAP(NavLinkViewController.java:1645)
           at com.navtech.atlas.NavLinkViewController$14.actionPerformed(NavLinkViewController.java:1535)
           at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
           at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
           at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
           at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
           at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
           at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:272)
           at java.awt.Component.processMouseEvent(Component.java:6216)
           at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
           at java.awt.Component.processEvent(Component.java:5981)
           at java.awt.Container.processEvent(Container.java:2041)
           at java.awt.Component.dispatchEventImpl(Component.java:4583)
           at java.awt.Container.dispatchEventImpl(Container.java:2099)
           at java.awt.Component.dispatchEvent(Component.java:4413)
           at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4556)
           at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4220)
           at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4150)
           at java.awt.Container.dispatchEventImpl(Container.java:2085)
           at java.awt.Window.dispatchEventImpl(Window.java:2475)
           at java.awt.Component.dispatchEvent(Component.java:4413)
           at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
           at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
           at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
           at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
           at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
           at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
           at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
      Caused by: java.util.ConcurrentModificationException
           at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
           at java.util.HashMap$KeyIterator.next(HashMap.java:828)
           at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1010)
           at com.navtech.val.validation.FirstClass.findExceptions(FirstClass.java:187)
           at com.navtech.val.validation.DeltaLinkAdjacentLinkCondition.runAllDeltas(DeltaLinkAdjacentLinkCondition.java:119)
           at com.navtech.val.DeltaValidationCommand.exec(DeltaValidationCommand.java:80)
           at com.navtech.val.service.MultiThreadedDeltaValidationService.executeDeltaValidationCommand(MultiThreadedDeltaValidationService.java:264)
           at com.navtech.val.service.MultiThreadedDeltaValidationService$InThreadDeltaValidationCallable.call(MultiThreadedDeltaValidationService.java:213)
           at com.navtech.val.service.MultiThreadedDeltaValidationService$InThreadDeltaValidationCallable.call(MultiThreadedDeltaValidationService.java:1)
           at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
           at java.util.concurrent.FutureTask.run(FutureTask.java:138)
           at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
           at java.lang.Thread.run(Thread.java:619)

      Edited by: 910816 on Jan 29, 2012 5:44 AM
        • 1. Re: Multithreading - Concurrent modification exception
          796440
          910816 wrote:
          Can you suggest something ?*
          I suggest in the future you do some research, like reading the Exception's documentation, googling for that exception and how to prevent it, and studying the basics of multithreading before writing multithreaded code. :-)

          I also suggest you either a) Synchronize all access to that collection explicitly, b) Use one of the Collections.synchronizedXxx() methods (which will still require syncing around the iteration), or c) Use an appropriate java.util.concurrent class (which may still require some syncing--I don't know as I haven't read your code).

          I also recommend you use code tags in the future when posting code, so that it will be readable: https://forums.oracle.com/forums/ann.jspa?annID=1429
          • 2. Re: Multithreading - Concurrent modification exception
            913819
            Tried something which works but it may not be a perfect fix.

            In FirstClass.java
            Changed this line
            Set allExceptions = mapC.findValidationExceptionsByMapObject(id);
            to
            Set allExceptions = new HashSet(mapC.findValidationExceptionsByMapObject(id)); 
            So in other words, when faced with concurrency issues the best solution would be to synchronize blocks of code that modifies the variables but in situation like below where modification of a variable is happening in one class and it is being simply read in another class, you can make a copy of the variable at the time of reading.

            Abhi
            • 3. Re: Multithreading - Concurrent modification exception
              EJP
              Not a solution. It just moves the problem, to inside the constructor new HashSet(Set). That iterates over the supplied Set to get its contents.
              • 4. Re: Multithreading - Concurrent modification exception
                796440
                910816 wrote:
                So in other words, when faced with concurrency issues the best solution would be to synchronize blocks of code that modifies the variables
                No. The only solution is to synchronize all access to shared variables. ^1^
                but in situation like below where modification of a variable is happening in one class and it is being simply read in another class, you can make a copy of the variable at the time of reading.
                You mean make a copy of the object. Make sure you understand the difference between a variable (which just holds a reference) and the object it points to. Copying a variable does nothing here.

                In the case of copying the object, no that's not sufficient, because it's not an atomic operation, so you need to sync around that copy operation as well.

                When all is said and done, if you have shared data, use synchronization. Trying to find "tricks" to get around it will just make your code more complicated, and make it not work correctly.

                ^1^ In some cases, using volatile is sufficient, and since the java.util.concurrent stuff was added in 1.5, we can do away with a lot of syncing in our code. Those classes may or may not used "synchronized" in a given situation. Utimately, though it all boils down to the same thing.