//aufgerufen vom Datenbank-Thread
private void updateAgentData() {
Iterator<Map.Entry<String, Agent>> it =
agent_map.entrySet().iterator();
Agent agent;
String agent_id = "";
while (it.hasNext()) {
Map.Entry<String, Agent> entry = it.next();
agent_id = entry.getKey();
agent = entry.getValue();
...mach was mit Objekt "agent"
Wenn sich genau zu diesem Zeitpunkt ein Client abmeldet, wird das Objekt
Agent über den Client-Thread während der Iteration gelöscht
(agent_map.remove(agent_id)). Obwohl ich die Map agent_map mit
synchronized angelegt habe,
private static Map<String, Agent> agent_map =
Collections.synchronizedMap(new HashMap<String, Agent>());
erhalte ich dennoch den Ausnahmefehler ConcurrentModificationException
Exception in thread "Timer-0" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:810)
at java.util.HashMap$EntryIterator.next(HashMap.java:851)
at java.util.HashMap$EntryIterator.next(HashMap.java:849)
Warum? Ich dachte, dass Modifikationen an einer Liste während einer
Iteration so verhindert werden?
Gruß, Thomas
> private static Map<String, Agent> agent_map =
> Collections.synchronizedMap(new HashMap<String, Agent>());
>
> erhalte ich dennoch den Ausnahmefehler ConcurrentModificationException
>
> Exception in thread "Timer-0" java.util.ConcurrentModificationException
> at java.util.HashMap$HashIterator.nextEntry(HashMap.java:810)
> at java.util.HashMap$EntryIterator.next(HashMap.java:851)
> at java.util.HashMap$EntryIterator.next(HashMap.java:849)
>
> Warum? Ich dachte, dass Modifikationen an einer Liste während einer
> Iteration so verhindert werden?
Wie sollte das in der Praxis sinnvoll bewerkstelligt werden?
| It is imperative that the user manually synchronize on the returned
| map when iterating over any of its collection views:
|
| Map m = Collections.synchronizedMap(new HashMap());
| ...
| Set s = m.keySet(); // Needn't be in synchronized block
| ...
| synchronized(m) { // Synchronizing on m, not s!
| Iterator i = s.iterator(); // Must be in synchronized block
| while (i.hasNext())
| foo(i.next());
| }
[API-Doc zu Collections#synchronizedMap()]
Die bessere Loesung waere hier wohl ein interner Iterator - in Java mit
brauchbarer Syntax voraussichtlich um das Jahr 2058 zu haben. :/
Viele Gruesse,
Patrick
Danke funktioniert. Den Ausnahmefehler konnte ich nicht mehr provozieren.
Set<Map.Entry<String, Agent>> s = agent_map.entrySet();
synchronized (agent_map) {
Agent agent;
String agent_id = "";
Iterator<Map.Entry<String, Agent>> it = s.iterator();
while (it.hasNext()) {
Map.Entry<String, Agent> map = it.next();
agent_id = map.getKey();
agent = map.getValue();
Viele Grüße, Thomas
Etwas einfacher:
synchronized (agent_map) {
for(Map.Entry<String, Agent> entry:agent_map.entrySet()) {
String agent_id=entry.getKey();
Agent agent=entry.getValue();
//mach was mit Agent
}
}
Sascha Broich
--
Eine nicht ernstlich gemeinte Willenserklärung, die in
der Erwartung abgegeben wird, der Mangel der Ernstlichkeit
werde nicht verkannt werden, ist nichtig.
(§ 118 BGB - Mangel der Ernstlichkeit)