Eslatma muallifi Krakovdan (Polsha) dasturiy ta'minot ishlab chiqaruvchisi Grzegorz Mirek. U Javada taxminan 6 yil oldin, universitetda o'qib yurgan vaqtlarida rivojlana boshlagan va o'sha paytdan beri bu sohada o'z mahoratini tinimsiz sayqallab kelmoqda. U, ayniqsa, JVM ishlashi va optimallashtirishga qiziqadi, u asosan o'z blogida nima haqida yozadi .
Java intervyusining eng mashhur savollaridan ba'zilari quyidagilardan iborat: Fast-fast va muvaffaqiyatsiz iteratorlar o'rtasidagi farq nima? Bunga eng soddalashtirilgan javob: Ishlamay qolgan iterator, agar to'plam iteratsiya paytida o'zgarsa, ConcurrentModificationException ni chiqaradi, lekin muvaffaqiyatsiz iterator o'zgarmasa. Garchi bu juda mazmunli bo'lib tuyulsa-da, suhbatdoshning xatoga yo'l qo'ymaslik deganda nimani nazarda tutayotgani noma'lumligicha qolmoqda? Java tili spetsifikatsiyalari bu atamani iteratorlarga nisbatan aniqlamaydi. Biroq, to'rtta raqobatbardosh o'zgartirish strategiyasi mavjud.
Raqobatli modifikatsiya
Birinchidan, raqobatbardosh (yoki parallel) modifikatsiya nima ekanligini aniqlaylik. Aytaylik, bizda to'plam bor va iterator faol bo'lganda, bu iteratordan kelmaydigan ba'zi o'zgarishlar yuz beradi. Bunday holda, biz raqobatbardosh modifikatsiyani olamiz. Sizga oddiy misol keltiraman: deylik, bizda bir nechta mavzu bor. Birinchi ip takrorlanadi, ikkinchi ip esa bir xil to'plamga elementlarni kiritadi yoki olib tashlaydi. Biroq, biz bitta oqimli muhitda ishlaganda ConcurrentModificationException ni olishimiz mumkin: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
Muvaffaqiyatsiz
Yuqoridagi kod fragmenti muvaffaqiyatsiz tez iteratorga misoldir . Ko'rib turganingizdek, iteratordan ikkinchi elementni olishga urinayotganda ConcurrentModificationException yuborildi . Iterator to'plam yaratilganidan beri o'zgartirilganligini qanday biladi? Misol uchun, to'plamda sana/vaqt tamg'asi bo'lishi mumkin, aytaylik lastModified . Iteratorni yaratishda siz ushbu maydonni nusxalashingiz va uni iterator ob'ektida saqlashingiz kerak. Keyin, har safar keyingi() usuli chaqirilganda, siz kollektsiyadagi lastModified qiymatini iterator nusxasi bilan solishtirasiz . Juda o'xshash yondashuv, masalan, ArrayList sinfini amalga oshirishda qo'llaniladi . Unda modCount misol oʻzgaruvchisi mavjud boʻlib , u roʻyxat necha marta oʻzgartirilganligini saqlaydi:final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Shuni ta'kidlash kerakki, muvaffaqiyatsiz tez iteratorlar eng zo'r asosda ishlaydi, ya'ni bir vaqtning o'zida o'zgartirilganda ConcurrentModificationException bekor qilinishiga kafolat yo'q. Shuning uchun siz ularga ishonmasligingiz kerak - aksincha, ular xatolarni aniqlash uchun ishlatilishi kerak. Bir vaqtning o'zida bo'lmagan to'plamlarning aksariyati muvaffaqiyatsiz tez iteratorlarni ta'minlaydi.
Zaif izchillik
Java.util.concurrent paketidagi (masalan , ConcurrentHashMap va most Queue kabi ) ko'pchilik bir vaqtda to'plamlar zaif izchil iteratorlarni ta'minlaydi. Ushbu atamaning ma'nosi hujjatlarda juda yaxshi tushuntirilgan :- Ular boshqa operatsiyalar bilan bir vaqtda qayta ishlanishi mumkin
- Ular hech qachon ConcurrentModificationException ni tashlamaydilar
- Ular iterator aynan bir marta yaratilgan vaqtda mavjud elementlarni kesib o'tishlari kafolatlanadi va keyingi o'zgartirishlarni aks ettirishi mumkin (lekin talab qilinmaydi).
GO TO FULL VERSION