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
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.