Sobes.tech
Middle

Hogyan kerülhető el a ConcurrentModificationException kivétel a gyűjtemény bejárásakor?

sobes.tech MI

Válasz az MI-től

Annak érdekében, hogy elkerüljük a ConcurrentModificationException-t a kollekciók bejárásakor, a következő megközelítéseket lehet alkalmazni:

  1. Szálbiztos kollekciók használata: A java.util.concurrent biztosít szálbiztos alternatívákat a standard kollekciókhoz. Például:

    • CopyOnWriteArrayList a ArrayList helyett
    • CopyOnWriteArraySet a HashSet helyett
    • ConcurrentHashMap a HashMap helyett
    // Példa CopyOnWriteArrayList használatára
    import java.util.concurrent.CopyOnWriteArrayList;
    import java.util.Iterator;
    
    public class ConcurrentCollectionExample {
        public static void main(String[] args) {
            CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
            list.add("A");
            list.add("B");
            list.add("C");
    
            // Az iterator nem dob `ConcurrentModificationException`-t
            Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()) {
                String element = iterator.next();
                System.out.println(element);
                // A kollekció módosítása iterálás közben biztonságos
                if (element.equals("B")) {
                    list.remove(element);
                }
            }
            System.out.println("Végső lista: " + list);
        }
    }
    
  2. A kollekció zárolása: Szinkronizálja a hozzáférést a kollekcióhoz a synchronized vagy a java.util.concurrent.locks használatával.

    // Példa szinkronizált blokkal
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    public class SynchronizedCollectionExample {
       public static void main(String[] args) {
           List<String> list = new ArrayList<>();
           list.add("A");
           list.add("B");
           list.add("C");
    
           synchronized (list) { // A kollekció zárolása
               Iterator<String> iterator = list.iterator();
               while (iterator.hasNext()) {
                   String element = iterator.next();
                   System.out.println(element);
                   // Itt nem szabad módosítani a kollekciót, ha más szál hozzáférhet
               }
           }
           // A kollekció módosítása a szinkronizált blokk kívül vagy más szál által
           // még mindig `ConcurrentModificationException`-t okozhat párhuzamos iterálás során
       }
    }
    
  3. Iterator használata az elemek törléséhez: Ha elemeket kell törölni az iterálás közben, használja az iterator remove() metódusát (ha támogatott a kollekció).

    // Törlés példája az Iterator.remove() segítségével
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    public class IteratorRemoveExample {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("A");
            list.add("B");
            list.add("C");
    
            Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()) {
                String element = iterator.next();
                System.out.println(element);
                // Az elem biztonságosan törölhető az iterator segítségével
                if (element.equals("B")) {
                    iterator.remove();
                }
            }
            System.out.println("Végső lista: " + list);
        }
    }
    
  4. Másolat iterálása: Hozzon létre másolatot a kollekcióból, és azzal iteráljon. A módosítások az eredeti kollekción nem befolyásolják az iterációt.

    // Másolaton való iterálás példája
    import java.util.ArrayList;
    import java.util.List;
    
    public class CopyIterationExample {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("A");
            list.add("B");
            list.add("C");
    
            // Másolat készítése az iteráláshoz
            List<String> copyList = new ArrayList<>(list);
    
            for (String element : copyList) {
                System.out.println(element);
                // A kollekció módosítása az eredeti listán a másolaton való iterálás közben
                if (element.equals("B")) {
                    list.remove(element);
                }
            }
            System.out.println("Végső lista: " + list);
        }
    }
    

A megközelítés kiválasztása a konkrét követelményektől függ: szükséges-e a kollekció módosítása az iterálás közben, mennyire fontos a teljesítmény, és a kód több szálon fut-e. A CopyOnWriteArrayList/CopyOnWriteArraySet akkor alkalmas, ha az olvasások száma jelentősen nagyobb, mint az írásoké. A zárolás akkor megfelelő, ha a módosítások ritkák, de lehetnek gyakrabban, mint a CopyOnWrite használatával. Az Iterator.remove() vagy a másolat iterálása akkor alkalmazható, ha a módosítások csak egy iteráció vagy szál keretében történnek.