Les Modifications Simultanées Exception

Je suis actuellement en train de travailler sur une application multi-thread, et il m'arrive parfois de recevoir simultanément modification exception (environ une fois ou deux fois par heure en moyenne, mais survenant à des intervalles apparemment aléatoires).

La mauvaise classe est essentiellement un wrapper pour une carte -- qui s'étend LinkedHashMap (avec accessOrder la valeur true). La classe dispose de quelques méthodes:

synchronized set(SomeKey key, SomeValue val)

La méthode set ajoute une paire clé/valeur à l'intérieur de la carte, et est protégé par le mot-clé synchronized.

synchronized get(SomeKey key)

La méthode get renvoie la valeur basée sur la touche d'entrée.

rebuild()

La carte interne est reconstruite une fois dans un certain temps (environ toutes les 2 minutes, les intervalles ne correspondent pas avec les exceptions). La reconstruction de la méthode essentiellement reconstruit les valeurs en fonction de leurs clés. Depuis la reconstruction() est assez cher, je n'ai pas mis un mot-clé synchronized sur la méthode. Au lieu de cela, je suis en train de faire:

public void rebuild(){
  /* initialization stuff */
  List<SomeKey> keysCopy = new ArrayList<SomeKey>();
  synchronized (this) {
    keysCopy.addAll(internalMap.keySet());
  }
  /* 
    do stuff with keysCopy, update a temporary map
   */    
  synchronized (this) {
    internalMap.putAll(tempMap);
  }
}

L'exception se produit à

keysCopy.addAll(internalMap.keySet());

À l'intérieur du bloc synchronisé.

Suggestions sont grandement appréciés. Se sentir libre pour me pointer vers des pages ou chapitres de Efficace Java et/ou de la Simultanéité dans la Pratique.

Mise à jour 1:

Aseptisé stacktrace:

java.util.ConcurrentModificationException
        at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:365)
        at java.util.LinkedHashMap$KeyIterator.next(LinkedHashMap.java:376)
        at java.util.AbstractCollection.toArray(AbstractCollection.java:126)
        at java.util.ArrayList.addAll(ArrayList.java:473)
        at a.b.c.etc.SomeWrapper.rebuild(SomeWraper.java:109)
        at a.b.c.etc.SomeCaller.updateCache(SomeCaller.java:421)
        ...

Mise à jour 2:

Merci à tous pour les réponses. Je pense que le problème réside dans le LinkedHashMap et ses accessOrder attribut, bien que je ne suis pas tout à fait certain de l'atm (enquête).

Si accessOrder sur une LinkedHashMap est définie à vrai, et je accéder à ses keySet ensuite ajoutez le jeu de clés à une linkedList via addAll, faire une de ces actions muter de la commande (compter pour un "accès")?

OT, mais arn-vous pas en danger de manquer toute modification de la classe dans le commentaire de la région entre les deux synchronisé méthodes de reconstruction()?
Oui, vous avez absolument raison; mais, selon la conception de documents, il est acceptable d'avoir un peu rassis de données 🙂
Merde, je souhaite que j'avais conception docs comme ça 😉
Désolé, mais pouvez-vous montrer à la déclaration et l'initialisation de la internalMap?
pourriez-vous également de montrer que ConcurrentModificationException pile

OriginalL'auteur Cambium | 2009-07-06