java.util.ConcurrentModificationException при перемещении jMapViewer

Я пытаюсь обновлять маркеры на jMapViewer один раз каждые 5 секунд. Кажется, это работает нормально, пока вы не переместите карту. В этот момент он бросает java.util.ConcurrentModificationException,

Я полагаю, что это связано с различными процессами, пытающимися одновременно получить доступ к списку маркеров карты, но я не уверен, как это исправить.

   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());
    }
}

Спасибо за вашу помощь.

Киран

1 ответ

Решение

Вы можете сделать это с помощью Semaphore, Mutex мониторsynchronized в сигнатуре метода) или блокировка (synchronize на объекте). Существуют также подходы без блокировок и без ожидания, но эти алгоритмы более сложны и полезны только при особых обстоятельствах.


Примеры

Проблема, вероятно, в том, что map Одновременно изменяется, используя блокировку, можно написать:

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());
    }
}

Это приводит к тому, что только один Thread может получить доступ map (если он запускает этот код). Если один поток находится в synchronize блок, все остальные потоки ждут в начале блока.

Проблема с этим подходом - так называемая проблема Читателей-Авторов. Большинство структур данных допускают чтение несколькими читателями, но если какой-то поток хочет что-то написать (также изменить что-либо), никакой читатель не может быть активным. В этом случае используется 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();
   }
}

Вы лучше использовать finally блоки, так что даже если Exception брошен, вы все еще разблокируете замок, иначе никакой другой объект не сможет войти в критическую секцию.

Другие вопросы по тегам