étude Java approfondie 07: ConcurrentModificationException anormale et CopyOnWriteArrayList

étude Java approfondie 07: ConcurrentModificationException anormale et CopyOnWriteArrayList

D'abord, regardez un seul fil lu Iterator Traversal anormale

1- code est le suivant: Créer une liste de tableaux, et ajouter trois éléments, ouvrir un fil, traverse le ArrayList, en lisant les données, alors que la suppression de données

publique  classe CopyOnWriteArrayListTest {
     publics  statiques  vides principaux (String [] args) { 
        CopyOnWriteArrayListThread t   = nouvelle CopyOnWriteArrayListThread ();
        pour ( int i = 0; i <1; i ++ ) {
             nouveau   fil (t) .start (); 
        } 
    } 
} 

Classe CopyOnWriteArrayListThread outils   Runnable {
     // 方式1 
    publique  statique Liste <String> list = nouvelle ArrayList <String> (); 

    statique { 
        list.add ("AA" ); 
        list.add ( "BB" ); 
        list.add ( "CC" ); 
    } 


    @Override 
    publique  vide run () { 
        Iterator <String> iterator = list.iterator ();
        tandis que (iterator.hasNext ()) { 
            String str = iterator.next (); 
            System.out.println (str); 

            si (str.equals ( "CC" )) { 
                list.remove (str); 
            } 
        } 
    } 
}

 

2- Les résultats sont comme suit: Rapport d'exception ConcurrentModificationException

java.util. ConcurrentModificationException 
    à java.util.ArrayList $ Itr.checkForComodification (ArrayList.java: 901 ) 
    à java.util.ArrayList $ Itr.next (ArrayList.java: 851 ) 
    à juc.concurrentmap.CopyOnWriteArrayListThread.run (CopyOnWriteArrayListTest.java: 42 ) 
    à java.lang.Thread.run (Thread.java: 748)

 

3- causes d'anomalie ConcurrentModificationException;

  Lorsque la méthode exécution iterator.next (), nous procéderons à un jugement checkForComodification interne (), quand ils jettent ConcurrentModificationException modCount = expectedModCount quand anormale !;

  Dans lequel, lorsque le nombre de fois ModCount ArrayList modifié enregistrer, de modifier les attentes nombre expectedModCount ArrayList est, sa valeur initiale ModCount;

   list.remove à l'intérieur (str) opération effectuée modCount ++, mais expectedModCount et la quantité de riz est mis à jour, de sorte que l'erreur;

publique suivant E () {
     checkForComodification ();
    int i = curseur;
    si (i> = taille)
         jette  nouvelle NoSuchElementException (); 
    Object [] elementData = ArrayList. ce .elementData;
    si (i> = elementData.length)
         lancer de  nouveaux ConcurrentModificationException (); 
    curseur = i + 1 ;
    retour (E) elementData [lastRet = i]; 
} 

Finale  vide checkForComodification () {
     si (modCount! =expectedModCount)
         lancer de  nouveaux ConcurrentModificationException (); 
}

 4 la solution mono-thread: changement list.remove (str) est Iterator.remove (); ArrayList méthode itérateur de suppression, dans lequel la valeur mise à jour expectedModCount

    @Override
     publique  vide run () { 
        Iterator <String> iterator = list.iterator ();
        tandis que (iterator.hasNext ()) { 
            String str = iterator.next (); 
            System.out.println (str); 

            si (str.equals ( "CC" )) { 
                Iterator.remove (); 
            } 
        } 
    }

 

privé  classe Itr outils Iterator <E> {
     // ArrayList中的Iterator supprimer方法
     publique  vide remove () {
             si (lastRet <0 )
                 lancer de  nouveaux IllegalStateException (); 
            checkForComodification (); 

            essayez { 
                ArrayList. ce .remove (lastRet); 
                curseur = lastRet; 
                lastRet = -1 ;
                expectedModCount = modCount; 
            } captures(IndexOutOfBoundsException ex) {
                 jeter  nouveau ConcurrentModificationException (); 
            } 
        }     
}       

 


 

En second lieu, multithread, même si Iterator.remove (), encore rapporté ConcurrentModificationException;

1- code est le suivant: créer une liste de tableaux, et à trois éléments, ouvert 10 fils, parcourir la liste de tableaux, tandis que la lecture des données, lors de la suppression des données

publique  classe CopyOnWriteArrayListTest {
     publics  statiques  vides principaux (String [] args) { 
        CopyOnWriteArrayListThread t   = nouvelle CopyOnWriteArrayListThread ();
        pour ( int i = 0; i < 10 ; i ++ ) {
             nouveau   fil (t) .start (); 
        } 
    } 
} 

Classe CopyOnWriteArrayListThread outils   Runnable {
     // 方式1 
    publique  statique Liste <String> list = nouvelle ArrayList <String> (); 

    statique {
        list.add ( "AA" ); 
        list.add ( "BB" ); 
        list.add ( "CC" ); 
    } 

    @Override 
    publique  vide run () { 
        Iterator <String> iterator = list.iterator ();
        tandis que (iterator.hasNext ()) { 
            String str = iterator.next (); 
            System.out.println (str); 
            si (str.equals ( "CC" )) {
                 Iterator.remove (); 
            } 
        } 
    } 
}

 journal d'exception

java.util. ConcurrentModificationException 
    à java.util.ArrayList $ Itr.checkForComodification (ArrayList.java: 901 ) 
    à java.util.ArrayList $ Itr.next (ArrayList.java: 851 ) 
    à juc.concurrentmap.CopyOnWriteArrayListThread.run (CopyOnWriteArrayListTest.java: 46 ) 
    à java.lang.Thread.run (Thread.java: 748)

! 2- Analyse du problème: la raison est encore modCount = expectedModCount cause, afin de comprendre les paramètres modCount appartiennent à la liste des objets, à savoir 10 fils d'un modCount public, mais expectedModCount appartiennent liste des objets Iterator, et la liste des objets Iterator dans chaque nouveau fil , recréée, le expectedModCount chaque fil sont indépendants les uns des autres, il va inévitablement conduire à « variable publique » modCount pas égale à la expectedModCount.

3- Solution: Utiliser des données de liste d'enregistrement CopyOnWriteArrayList, et les données sont supprimées en utilisant list.remove (str);

classe CopyOnWriteArrayListThread de   Runnable {
     // 方式2 
    CopyOnWriteArrayList de public static <String> Liste = new CopyOnWriteArrayList <String> (); 

    statique { 
        list.add ( "AA" ); 
        list.add ( "BB" ); 
        list.add ( "CC" ); 
    } 

    @Override 
    publique  vide run () { 
        Iterator <String> iterator = list.iterator ();
        tandis que (iterator.hasNext ()) { 
            String str = iterator.next (); 
            System.out.println (str);
            si (str.equals ( "CC" )) {
                 list.remove (str); 
            } 
        } 
    } 
}

 


 

En troisième lieu, le CopyOnWriteArrayList

Qu'est-ce que 1-CopyOnWriteArrayList qui?

  Selon les notes officielles: CopyOnWriteArrayList est ArrayList thread-safe, leur ajouter correspondant, supprimer et d'autres opérations de modification permettra également de créer une nouvelle copie

Comment 2-CopyOnWriteArrayList thread-safe

  ajouter () et remove (): CopyOnWriteArrayList plus grande caractéristique de la classe est, après l'opération à modifier (ajouter / supprimer, etc.) et crée une nouvelle données de modification, des exemples de celle-ci la modification est terminée, le point de référence original au nouveau tableau. Ainsi, le processus de modification ne modifie pas le tableau original. Il n'y aura pas d'erreur de ConcurrentModificationException.

    // CopyOnWriteArrayList中的ajouter方法
    publique  booléen add (E e) {
         finale verrouillage de ReentrantLock = ce .lock;
       serrure.Serrure ();
        essayez {
             Object [] éléments = GetArray (); 
            int len = elements.length; 
            Object [] = newElements Arrays.copyOf (éléments, len + 1); 
            newElements [len] = e; 
            setArray (newElements); 
            retour  vrai ; 
        } Enfin {
             lock.unlock (); 
        } 
    } 
     //CopyOnWriteArrayList中的supprimer方法,调用下面的supprimer (o, instantané, index) du 
    public  boolean remove (Object o) { 
        Object [] instantané = getArray ();
        int index = indexOf (o, instantané, 0 , snapshot.length);
        retour (indice <0)? faux : supprimer (o, instantané, index); 
    } 
     // 真正的supprimer方法
    privé  booléenne supprimer (o Object, Object [] instantané, int index) {
         finale verrouillage de ReentrantLock = ce .lock;
        serrure.Serrure ();
        essayez { 
            courant Object [] =getArray ();
            int len = current.length;
            si (instantané =! courant) FindIndex: {
                 int préfixe = Math.min (index, len);
                pour ( int i = 0; i <préfixe; i ++ ) {
                     si (courant [i] = instantané [i] &&! eq (o, courant [i])) { 
                        indice = i;
                        rompre FindIndex; 
                    } 
                } 
                Si (index> = len)
                     retour  faux;
                si ([index] courant == o)
                     rompre FindIndex; 
                index = indexOf (o, courant, index, LEN);
                si (indice <0 )
                     retour  faux ; 
            }             Object [] newElements
 = new Object [len - 1]; 
            System.arraycopy (courant, 0, 0, newElements, index); 
            System.arraycopy (courant, index + 1, 
                             newElements, index, 
                             len - index - 1); 
            setArray (newElements); 
            retour  vrai; 
        } Enfin {
             lock.unlock (); 
        } 
    }

 

avoir()

        // CopyOnWriteArrayList中的get方法
      publique get E ( int index) {
             finale serrure ReentrantLock = l.lock;
            serrure.Serrure ();
            essayer { 
                rangeCheck (index); 
                checkForComodification (); 
                retour l.get (index + offset); 
            } Enfin {
                 lock.unlock (); 
            } 
        }    

 

Je suppose que tu aimes

Origine www.cnblogs.com/wobuchifanqie/p/12510537.html
conseillé
Classement