Java ConcurrentModificationException Ne Demek? ConcurrentModificationException Hatası

Share

Java programlamada karşılaşılan ConcurrentModificationException hatası, genellikle bir koleksiyon üzerinde eşzamanlı (concurrent) değişiklik yapma girişiminde bulunulduğunda ortaya çıkan bir istisna türüdür. Bu makalede, ConcurrentModificationException hatasının ne anlama geldiğini, neden oluştuğunu ve bu hatayı çözmek için alınabilecek önlemleri detaylı bir şekilde inceleyeceğiz.

1. ConcurrentModificationException Nedir?

ConcurrentModificationException, bir koleksiyonun üzerinde eşzamanlı olarak (paralel olarak) yapılan değişikliklerin uyumsuzluğu sonucu meydana gelir. Örneğin, bir Iterator kullanılarak koleksiyon üzerinde dönerken, bu sırada koleksiyona eleman eklenirse veya silinirse, ConcurrentModificationException hatası ortaya çıkar.

2. Nedenleri ve Senaryolar

2.1. Iterator ile Eşzamanlı Eleman Ekleme:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ConcurrentModificationException;

public class ConcurrentModificationExceptionExample {
    public static void main(String[] args) {
        List<String> myList = new ArrayList<>();
        myList.add("Java");
        myList.add("Python");

        Iterator<String> iterator = myList.iterator();

        while (iterator.hasNext()) {
            String element = iterator.next();
            // Eşzamanlı olarak eleman eklenmesi ConcurrentModificationException'a neden olur
            myList.add("C++"); // ConcurrentModificationException
        }
    }
}

Bu örnekte, Iterator kullanılarak koleksiyon üzerinde dönerken, aynı anda koleksiyona eleman eklenmesi ConcurrentModificationException hatasına neden olur.

2.2. Iterator ile Eşzamanlı Eleman Silme:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ConcurrentModificationException;

public class ConcurrentModificationExceptionExample {
    public static void main(String[] args) {
        List<String> myList = new ArrayList<>();
        myList.add("Java");
        myList.add("Python");

        Iterator<String> iterator = myList.iterator();

        while (iterator.hasNext()) {
            String element = iterator.next();
            // Eşzamanlı olarak eleman silinmesi ConcurrentModificationException'a neden olur
            myList.remove("Java"); // ConcurrentModificationException
        }
    }
}

Bu örnekte, Iterator kullanılarak koleksiyon üzerinde dönerken, aynı anda koleksiyondan eleman silinmesi ConcurrentModificationException hatasına neden olur.

3. Çözümler ve Örnekler

3.1. Iterator’un remove Metodunu Kullanma:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ConcurrentModificationExceptionSolution {
    public static void main(String[] args) {
        List<String> myList = new ArrayList<>();
        myList.add("Java");
        myList.add("Python");

        Iterator<String> iterator = myList.iterator();

        while (iterator.hasNext()) {
            String element = iterator.next();
            iterator.remove(); // Iterator'un remove metodunu kullanarak güvenli bir şekilde elemanı silebiliriz
        }

        System.out.println("Modified List: " + myList);
    }
}

Bu örnekte, Iterator’un remove metodunu kullanarak koleksiyon üzerinde eşzamanlı değişiklik yapılabilir.

3.2. Iterator Kullanımını Sadece Okuma İçin Sınırlama:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ConcurrentModificationExceptionSolution {
    public static void main(String[] args) {
        List<String> myList = new ArrayList<>();
        myList.add("Java");
        myList.add("Python");

        Iterator<String> iterator = myList.iterator();

        // Sadece okuma amaçlı kullanım, eşzamanlı değişikliklere izin vermez
        while (iterator.hasNext()) {
            String element = iterator.next();
            System.out.println(element);
        }

        System.out.println("List: " + myList);
    }
}

Bu örnekte, sadece okuma amaçlı olarak Iterator kullanmak ve eşzamanlı değişikliklerden kaçınmak mümkündür.

Örnek 3: Eşzamanlı Modifikasyon Yapan Diğer İş Parçacıkları:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ConcurrentModificationExceptionExample {
    public static void main(String[] args) throws InterruptedException {
        List<String> myList = new ArrayList<>();
        myList.add("Java");
        myList.add("Python");

        // Bir iş parçacığı koleksiyona eleman ekler
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000); // 1 saniye bekleyerek ana iş parçacığını çalıştırmadan önce koleksiyona eleman ekleyelim
                myList.add("C++");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Iterator<String> iterator = myList.iterator();

        // İteratörle koleksiyon üzerinde dönülüyor
        thread.start(); // Diğer iş parçacığı başlatılıyor
        while (iterator.hasNext()) {
            String element = iterator.next();
            System.out.println(element);
            Thread.sleep(500); // Her elemanı işleme aldıktan sonra 0.5 saniye bekleyelim
        }

        thread.join(); // Diğer iş parçacığının tamamlanmasını bekleyelim
    }
}

Bu örnekte, bir iş parçacığı koleksiyona eleman eklerken, diğer iş parçacığı ise aynı anda koleksiyon üzerinde iterasyon yapmaya çalışıyor. Bu durumda, ConcurrentModificationException hatası meydana gelir.

Detaylar ve Çözümler:

  1. Senkronizasyon veya Thread Güvenliği:
    • Eşzamanlı modifikasyonlardan kaçınmak için senkronizasyon veya thread güvenliği kullanılabilir.
    • Collections.synchronizedList veya CopyOnWriteArrayList gibi senkronize koleksiyonlar kullanarak bu hatadan kaçınılabilir.

Örnek 4: Eşzamanlı Modifikasyon Yapan Farklı İşlemler:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ConcurrentModificationExceptionExample {
    public static void main(String[] args) {
        List<String> myList = new ArrayList<>();
        myList.add("Java");
        myList.add("Python");

        Iterator<String> iterator = myList.iterator();

        // İteratörle koleksiyon üzerinde dönülüyor
        while (iterator.hasNext()) {
            String element = iterator.next();
            System.out.println(element);

            // Eşzamanlı olarak başka bir işlem koleksiyona eleman eklerse ConcurrentModificationException hatası alınır
            if (element.equals("Java")) {
                myList.add("C++"); // ConcurrentModificationException
            }
        }
    }
}

4. Özet ve Sonuç

ConcurrentModificationException, eşzamanlı olarak bir koleksiyon üzerinde değişiklik yapma girişiminde bulunulduğunda ortaya çıkan bir hata türüdür. Bu hatayı önlemek için Iterator’un remove metodunu kullanmak veya sadece okuma amaçlı Iterator kullanmak gibi önlemler alınabilir. Eşzamanlı değişikliklerin yapılmadığından emin olmak, Java uygulamalarının daha güvenilir ve hatasız çalışmasına katkı sağlar.

Author