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
брошен, вы все еще разблокируете замок, иначе никакой другой объект не сможет войти в критическую секцию.