Bir Modifikasyonu Collection
iterating ise o aracılığıyla Collection
bir kullanarak Iterator
edilir izin verilmez çoğu tarafından Collection
sınıfları. Java kitaplığı, bir Collection
sü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ığı Collection
kullanarak Collection.iterator()
, (kullanarak veya gelişmiş bir for
döngü kullanarak) için bir yineleyici oluşturmak , yinelemeye başlamak (kullanarak Iterator.next()
veya gelişmiş for
döngü gövdesine eşdeğer bir şekilde girmek ), öğesini değiştirmek ve Collection
ardı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 .Collection
ConcurrentModificationException
Collection
ConcurrentModificationException
Belgeleri ConcurrentModificationException
diyor 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
, TreeSet
ve ArrayList
sı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, Iterator
atar 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.
Map
Arayü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, ConcurrentModificationException
eş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, IllegalStateException
eş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 ConcurrentModificationException
a'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 ConcurrentModificationException
gö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 Collection
nesne. Ardından, bu nesnenin nereden değiştirilebileceğini incelemelisiniz.
- En yaygın nedeni modifikasyonu olan
Collection
gelişmiş bir mesafede for
fazla döngü Collection
. Iterator
Kaynak kodunuzda bir nesne görmemeniz, orada olmadığı anlamına gelmez Iterator
! Neyse ki, hatalı for
döngünün ifadelerinden biri genellikle yığın izlemede olacaktır, bu nedenle hatayı bulmak genellikle kolaydır.
- Daha zor bir durum, kodunuzun
Collection
nesneye 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 Collection
gibi alt listeleri , Map
giriş setleri ve Map
anahtar 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
Collection
bazı 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 Collection
nesneye sınırlayın , böylece eşzamanlı değişiklikleri önlemek daha kolay olur. Make Collection
a private
nesne ya da yerel bir değişken ve başvurular dönmüyor Collection
yöntemleri veya Yineleyicilerin. Daha sonra değiştirilebilecek tüm yerleri incelemek çok daha kolaydır Collection
. Eğer Collection
birden fazla iş parçacığı tarafından kullanılacaksa, dişlilerin Collection
yalnızca uygun senkronizasyon ve kilitleme ile erişmesini sağlamak pratiktir .