Search code examples
javajmapviewer

java.util.ConcurrentModificationException on moving jMapViewer


I'm trying to update markers on a jMapViewer once every 5 seconds. This seems to be working fine until you move the map. At this point it throws a java.util.ConcurrentModificationException.

I believe this is to do with the different processes trying to access the map markers list at the same time but I'm not sure how to fix it.

   timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            loadUnits();
        }
    }, 5 * 1000, 5 * 1000);

   private void loadUnits() {      
    String query = "SELECT callsign, currentlat,currentlon,previouslat,previouslon,    mobile, uniticon FROM unit WHERE isdeleted=0;";
    rs = DBase.runQuery(query);
    kit.removeAllMapMarkers();
    MapMarkerUnit x;
    try {
        while (rs.next()) {
           x = new MapMarkerUnit(rs.getDouble("currentlat"),rs.getDouble("currentlon"));
           if (rs.getInt("mobile") == 1) x.setMovement(true);
           else x.setMovement(false);
           x.setIconName(rs.getString("uniticon"));
           x.setPriority(1);
           kit.addMapMarker(x);
        }
    }
    catch (SQLException e) {
        System.out.print(e.toString());
    }
}

Thanks for your help.

Kieran


Solution

  • You can do this using a Semaphore, Mutex, a monitor (with synchronized in the method signature) or a lock (synchronize on object). There exist lock-free and wait-free approaches as well, but these algorithms are more complex and are only useful under special circumstances.


    Examples

    The problem is probably that map is modified concurrently, using a lock, one can write:

    synchronize(map) {
        map.removeAllMapMarkers();
        MapMarkerUnit x;
        try {
            while (rs.next()) {
               x = new MapMarkerUnit(rs.getDouble("currentlat"),rs.getDouble("currentlon"));
               if (rs.getInt("mobile") == 1) x.setMovement(true);
               else x.setMovement(false);
               x.setIconName(rs.getString("uniticon"));
               x.setPriority(1);
               map.addMapMarker(x);
            }
        }
        catch (SQLException e) {
            System.out.print(e.toString());
        }
    }
    

    This results in the fact that only one Thread can access map (if it runs this code). If one thread is in the synchronize block, all other threads wait at the beginning of the block.

    A problem with this approach is the so called Readers-Writers problem. Most datastructures allow to be read by multiple Readers, but if some Thread want to write something (modify something as well), no Reader can be active. In that case one uses a ReadWriteLock:

    private ReadWriteLock rwl = new ReentrantReadWriteLock();
    
    public void writeSomething() {
       rwl.writeLock().lock();
       try {
          //Modify/write something
       } finally {
          rwl.writeLock().unlock();
       }
    }
    
    public String readSomething() {
       rwl.readLock().lock();
       try {
          //Read something
       } finally {
          rwl.readLock().unlock();
       }
    }
    

    You better use finally blocks so that even if an Exception is thrown you still unlock the lock, otherwise no other object will be able to enter the critical section.