Жазбаның авторы - Краковтан (Польша) бағдарламалық жасақтама жасаушы Гжегож Мирек. Ол Java-да шамамен 6 жыл бұрын университетте оқып жүргенде дамыды және сол уақыттан бері ол осы саладағы дағдыларын жалықпай жылтыратып келеді. Ол әсіресе JVM өнімділігі мен оңтайландыруына қызығушылық танытады, ол негізінен блогында бұл туралы жазады .
Ең танымал Java сұхбат сұрақтарының кейбірі мыналарды қамтиды: сәтсіздікке ұшырамайтын және қатесіз итераторлардың айырмашылығы неде? Бұған ең жеңілдетілген жауап мынада: сәтсіз итератор, егер жинақ итерация кезінде өзгерсе, ConcurrentModificationException шығарады, бірақ қатесіз итератор өзгермейді. Бұл өте мағыналы болып көрінгенімен, сұхбат алушының қателіктен қорғау дегенді білдіретіні түсініксіз. Java тілінің техникалық сипаттамалары итераторларға қатысты бұл терминді анықтамайды. Дегенмен, бәсекеге қабілетті модификацияның төрт стратегиясы бар.
Бәсекелестік модификация
Алдымен, бәсекелестік (немесе параллель) модификацияның не екенін анықтайық. Бізде жинақ бар делік және итератор белсенді болған кезде, осы иератордан келмейтін кейбір өзгерістер орын алады. Бұл жағдайда біз бәсекеге қабілетті модификация аламыз. Сізге қарапайым мысал келтірейін: бізде бірнеше ағындар бар делік. Бірінші ағын итерацияланады, ал екінші ағын сол жинақтағы элементтерді кірістіреді немесе жояды. Дегенмен, бір ағынды ортада іске қосылған кезде ConcurrentModificationException ала аламыз :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
Сәтсіз
Жоғарыдағы code фрагменті сәтсіз итератордың мысалы болып табылады . Көріп отырғаныңыздай, итератордан екінші элементті шығару әрекеті кезінде ConcurrentModificationException жіберілді . Итератор жинақ жасалғаннан бері өзгертілгенін қайдан біледі? Мысалы, коллекцияда күн/уақыт белгісі болуы мүмкін, айталық lastModified . Итераторды жасаған кезде осы өрісті көшіріп, оны иератор нысанында сақтау керек. Содан кейін келесі() әдісіне қоңырау шалған сайын коллекциядағы lastModified мәнін иератордан алынған көшірмемен салыстырасыз . Өте ұқсас тәсіл, мысалы, ArrayList класын іске асыруда қолданылады . Онда тізімнің қанша рет өзгертілгенін сақтайтын modCount айнымалысы бар :final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Сәтсіз итераторлар ең жақсы тұқым негізінде жұмыс істейтінін ескеру маңызды , яғни бір мезгілде өзгерту кезінде ConcurrentModificationException жойылатынына кепілдік жоқ . Сондықтан сіз оларға сенбеуіңіз керек - керісінше, қателерді анықтау үшін оларды пайдалану керек. Бір мезгілде емес жинақтардың көпшілігі сәтсіз итераторларды қамтамасыз етеді.
Әлсіз консистенциясы
Java.util.concurrent бумасындағы көптеген қатарлас жинақтар (мысалы, ConcurrentHashMap және Queue көпшілігі ) әлсіз дәйекті иераторларды қамтамасыз етеді. Бұл терминнің мағынасы құжаттамада өте жақсы түсіндіріледі :- Оларды басқа операциялармен қатар өңдеуге болады
- Олар ешқашан ConcurrentModificationException жібермейді
- Оларға итератор дәл бір рет жасалған кезде бар элементтерді айналып өтуге кепілдік беріледі және кейінгі өзгертулерді көрсете алады (бірақ талап етілмейді).
GO TO FULL VERSION