JavaRush /Java Blogu /Random-AZ /İki İteratorun Nağılı: Java-da Rəqabətli Modifikasiya Str...

İki İteratorun Nağılı: Java-da Rəqabətli Modifikasiya Strategiyaları

Qrupda dərc edilmişdir
Qeydin müəllifi Krakovdan (Polşa) proqram təminatı tərtibatçısı Qrzeqorz Mirekdir. O, təxminən 6 il əvvəl, hələ universitetdə oxuyarkən Java-da inkişaf etməyə başlayıb və o vaxtdan bu sahədə öz bacarıqlarını yorulmadan cilalayır. O, JVM performansı və optimallaşdırılması ilə xüsusilə maraqlanır, bu barədə əsasən bloqunda yazır .
İki İteratorun Nağılı: Java-da Rəqabətli Modifikasiya Strategiyaları - 1
Java-nın ən populyar müsahibə suallarından bəziləri bunlardır: Fast-fast və fail-safe iteratorlar arasında fərq nədir? Buna ən sadələşdirilmiş cavab belədir: Uğursuz-sürətli iterator, iterasiya zamanı kolleksiya dəyişirsə, ConcurrentModificationException atır, lakin uğursuz iterator dəyişmir. Bu kifayət qədər mənalı səslənsə də, müsahibin uğursuzluqla nə demək istədiyi aydın deyil? Java Dil Spesifikasiyaları bu termini iteratorlara münasibətdə müəyyən etmir. Bununla belə, dörd rəqabətli modifikasiya strategiyası mövcuddur.

Rəqabətli modifikasiya

Əvvəlcə rəqabətli (və ya paralel) modifikasiyanın nə olduğunu müəyyən edək. Tutaq ki, bizim kolleksiyamız var və iterator aktiv olduqda, bu iteratordan gəlməyən bəzi dəyişikliklər baş verir. Bu halda, biz rəqabətli modifikasiya alırıq. Sizə sadə bir misal verim: tutaq ki, bizdə bir neçə mövzu var. Birinci ip təkrarlanır və ikinci ip eyni kolleksiyadan elementləri daxil edir və ya çıxarır. Bununla belə, biz tək yivli mühitdə işləyərkən ConcurrentModificationException əldə edə bilərik:
List<String> cities = new ArrayList<>();
cities.add(Warsaw);
cities.add(Prague);
cities.add(Budapest);

Iterator<String> cityIterator = cities.iterator();
cityIterator.next();
cities.remove(1);
cityIterator.next(); // генерирует ConcurrentModificationException

Tez uğursuz

Yuxarıdakı kod parçası uğursuz sürətli iteratorun nümunəsidir . Gördüyünüz kimi, iteratordan ikinci elementi götürməyə çalışarkən ConcurrentModificationException atıldı . İterator kolleksiyanın yaradılandan bəri dəyişdirildiyini necə bilir? Məsələn, kolleksiyada tarix/saat möhürü ola bilər, deyək lastModified . İterator yaratarkən bu sahəni köçürməli və onu iterator obyektində saxlamalısınız. Sonra hər dəfə növbəti() metodu çağırılanda siz sadəcə olaraq kolleksiyadakı lastModified dəyərini iteratordan olan surətlə müqayisə edəcəksiniz . Çox oxşar yanaşma, məsələn, ArrayList sinifinin həyata keçirilməsində istifadə olunur . Siyahının neçə dəfə dəyişdirildiyini saxlayan modCount nümunə dəyişəninə malikdir :
final void checkForComodification() {
   if (modCount != expectedModCount)
       throw new ConcurrentModificationException();
}
Qeyd etmək vacibdir ki, uğursuz sürətli iteratorlar ən yaxşı cins əsasında işləyir, yəni paralel modifikasiya zamanı ConcurrentModificationException-ın atılacağına zəmanət yoxdur . Beləliklə, onlara etibar etməməlisiniz - daha doğrusu, səhvləri aşkar etmək üçün istifadə edilməlidir. Əksər paralel olmayan kolleksiyalar uğursuz sürətli iteratorları təmin edir.

Zəif Ardıcıllıq

Java.util.concurrent paketindəki əksər paralel kolleksiyalar (məsələn, ConcurrentHashMap və most Queue kimi ) zəif ardıcıl iteratorları təmin edir. Bu terminin mənası sənədlərdə çox yaxşı izah edilmişdir :
  • Onlar digər əməliyyatlarla eyni vaxtda işlənə bilər
  • Heç vaxt ConcurrentModificationException atmırlar
  • Onlara iteratorun tam olaraq bir dəfə yaradıldığı anda mövcud elementləri keçməsinə zəmanət verilir və sonrakı dəyişiklikləri əks etdirə bilər (lakin tələb olunmur).

Snapshot

Bu strategiya ilə iterator kolleksiyanın yaradıldığı andakı vəziyyəti ilə əlaqələndirilir - bu kolleksiyanın snapshotudur. Orijinal kolleksiyaya edilən hər hansı dəyişiklik əsas məlumat strukturunun yeni versiyasının yaradılması ilə nəticələnir. Bu, snapşotumuzu dəyişməz qoyur, buna görə də iterator yaradıldıqdan sonra kolleksiyada baş verən dəyişiklikləri əks etdirmir. Bu köhnə yaxşı kopya-on-yazma (COW) texnikasıdır . O, paralel modifikasiyalar problemini tamamilə həll edir, ona görə də bu yanaşma ilə ConcurrentModificationException yaradılmır. Bundan əlavə, iteratorlar elementləri dəyişdirən əməliyyatları dəstəkləmir. Kopya-on-yazma kolleksiyaları istifadə etmək üçün çox baha olur, lakin dəyişikliklər iterator keçidlərindən daha az tez-tez baş verirsə, onlardan istifadə etmək məntiqlidir. Nümunələr CopyOnWriteArrayListCopyOnWriteArraySet sinifləridir .

Müəyyən edilməmiş davranış

Siz VectorHashtable kimi köhnə kolleksiya növlərində qeyri-müəyyən davranışla qarşılaşa bilərsiniz . Hər ikisində standart uğursuz sürətli iteratorlar var, lakin əlavə olaraq, onlar Enumeration interfeysinin tətbiqlərindən istifadə etməyə imkan verir və eyni vaxtda modifikasiya zamanı necə davranacaqlarını bilmirlər. Bəzi elementlərin təkrarlanması və ya olmaması, hətta bəzi qəribə istisnalarla qarşılaşa bilərsiniz. Onlarla oynamamaq daha yaxşıdır!
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION