Bir Modifikasyonu Collectioniterating ise o aracılığıyla Collectionbir kullanarak Iteratoredilir izin verilmez çoğu tarafından Collectionsınıfları. Java kitaplığı, bir Collectionsüreyi yineleyerek bir "eşzamanlı değişiklik" değiştirme girişimini çağırır . Bu maalesef olası tek nedenin birden çok iş parçacığı tarafından eşzamanlı olarak değiştirildiğini gösteriyor, ancak bu öyle değil. Yalnızca bir iş parçacığı Collectionkullanarak Collection.iterator(), (kullanarak veya gelişmiş bir fordöngü kullanarak) için bir yineleyici oluşturmak , yinelemeye başlamak (kullanarak Iterator.next()veya gelişmiş fordöngü gövdesine eşdeğer bir şekilde girmek ), öğesini değiştirmek ve Collectionardından yinelemeye devam etmek mümkündür.
Programcılara yardımcı olmak için , bu sınıfların bazı uygulamaları, hatalı eşzamanlı değişiklikleri tespit etmeye ve bunu tespit ederse bir atmaya çalışır. Bununla birlikte, eşzamanlı tüm değişikliklerin tespitini garanti etmek genellikle mümkün ve pratik değildir. Bu yüzden yanlış kullanımı her zaman bir fırlatmaya neden olmaz .CollectionConcurrentModificationExceptionCollectionConcurrentModificationException
Belgeleri ConcurrentModificationExceptiondiyor ki:
Bu istisna, bu tür bir değişikliğe izin verilmezse, bir nesnenin eşzamanlı olarak değiştirilmesini tespit eden yöntemler tarafından atılabilir ...
Bu istisnanın her zaman bir nesnenin farklı bir iş parçacığı tarafından eşzamanlı olarak değiştirildiğini göstermediğini unutmayın. Tek bir iş parçacığı, bir nesnenin sözleşmesini ihlal eden bir dizi yöntem çağrısı yayınlarsa, nesne bu istisnayı atabilir ...
Eşzamanlı olmayan eşzamanlı değişikliklerin varlığında herhangi bir kesin garanti vermenin imkansız olduğu için başarısızlık hızlı davranışının garanti edilemeyeceğini unutmayın. Başarısızlık hızlı operasyonlar ConcurrentModificationException, en iyi çabayı temel alır.
Bunu not et
Dokümantasyonu HashSet, HashMap, TreeSetve ArrayListsınıfları bu diyor ki:
[Bu sınıftan doğrudan veya dolaylı olarak] döndürülen yineleyiciler başarısız olur: [koleksiyon], yineleyici oluşturulduktan sonra herhangi bir zamanda değiştirilirse, yineleyicinin kendi kaldırma yöntemi dışında herhangi bir şekilde, Iteratoratar a ConcurrentModificationException. Bu nedenle, eşzamanlı değişiklik karşısında yineleyici, gelecekte belirsiz bir zamanda keyfi, deterministik olmayan davranışları riske atmak yerine, hızlı ve temiz bir şekilde başarısız olur.
Eşzamanlı olmayan eşzamanlı değişikliklerin varlığında herhangi bir kesin garanti vermenin imkansız olduğu için, bir yineleyicinin başarısızlık hızlı davranışının garanti edilemeyeceğine dikkat edin. Başarısızlık hızlı yineleyiciler ConcurrentModificationException, en iyi çabayı temel alır. Bu nedenle, doğruluğu için bu istisnaya dayanan bir program yazmak yanlış olur : Yineleyicilerin hata-hızlı davranışı yalnızca hataları tespit etmek için kullanılmalıdır .
Davranışın "garanti edilemeyeceğini" ve yalnızca "en iyi çaba temelinde" olduğunu tekrar unutmayın.
MapArayüzün çeşitli yöntemlerinin dokümantasyonu şunu söylüyor:
Eşzamanlı olmayan uygulamalar bu yöntemi geçersiz kılmalıdır ve en iyi çaba temelinde, ConcurrentModificationExceptioneşleme işlevinin hesaplama sırasında bu haritayı değiştirdiği tespit edilirse bir a atmalıdır. Eşzamanlı uygulamalar bu yöntemi geçersiz kılmalı ve en iyi çaba temelinde, IllegalStateExceptioneşleme işlevinin hesaplama sırasında bu haritayı değiştirdiği ve sonuç olarak hesaplamanın asla tamamlanmayacağı tespit edilirse bir atılmalıdır .
Yine, algılama için yalnızca bir "en iyi çaba temeli" gerektiğini ve ConcurrentModificationExceptiona'nın yalnızca eşzamanlı olmayan (iş parçacığı güvenli olmayan) sınıflar için açıkça önerildiğini unutmayın.
Hata ayıklama ConcurrentModificationException
Bu nedenle, a nedeniyle bir yığın izleme ConcurrentModificationExceptiongördüğünüzde, nedeninin a'ya güvenli olmayan çok iş parçacıklı erişim olduğunu hemen varsayamazsınız Collection. Eğer gerekir yığın izlemesi incelemek hangi sınıfı belirlemek için Collectionözel durum (sınıfının bir yöntem doğrudan veya dolaylı olarak atılan sahip olur), ve bunun için Collectionnesne. Ardından, bu nesnenin nereden değiştirilebileceğini incelemelisiniz.
- En yaygın nedeni modifikasyonu olan
Collectiongelişmiş bir mesafede forfazla döngü Collection. IteratorKaynak kodunuzda bir nesne görmemeniz, orada olmadığı anlamına gelmez Iterator! Neyse ki, hatalı fordöngünün ifadelerinden biri genellikle yığın izlemede olacaktır, bu nedenle hatayı bulmak genellikle kolaydır.
- Daha zor bir durum, kodunuzun
Collectionnesneye yapılan referansların etrafından geçmesidir. O Not unmodifiable (ürettiği gibi koleksiyonların görünümleri Collections.unmodifiableList()böylece), değiştirilebilir koleksiyonuna bir başvuru korumak bir "unmodifiable" koleksiyonu istisnası atabilir üzerinde yineleme (modifikasyon başka yerde yapılmıştır). Diğer görünümler , aramalarınızdan Collectiongibi alt listeleri , Mapgiriş setleri ve Mapanahtar setleri de orijinal (değiştirilebilir) başvurular korumak Collection. Bu, iş parçacığı için güvenli olanlar için bile bir sorun olabilir Collection, örneğin CopyOnWriteList; iş parçacığı açısından güvenli (eşzamanlı) koleksiyonların hiçbir zaman istisna atamayacağını varsaymayın.
- Hangi işlemlerin a'yı değiştirebileceği
Collectionbazı durumlarda beklenmedik olabilir. Örneğin, LinkedHashMap.get()koleksiyonunu değiştirir .
- En zor durumlar, istisnanın birden çok iş parçacığı tarafından eşzamanlı değişikliklere bağlı olduğu durumlardır .
Eşzamanlı değişiklik hatalarını önlemek için programlama
Mümkün olduğunda, tüm başvuruları bir Collectionnesneye sınırlayın , böylece eşzamanlı değişiklikleri önlemek daha kolay olur. Make Collectiona privatenesne ya da yerel bir değişken ve başvurular dönmüyor Collectionyöntemleri veya Yineleyicilerin. Daha sonra değiştirilebilecek tüm yerleri incelemek çok daha kolaydır Collection. Eğer Collectionbirden fazla iş parçacığı tarafından kullanılacaksa, dişlilerin Collectionyalnızca uygun senkronizasyon ve kilitleme ile erişmesini sağlamak pratiktir .