JavaRush /Java блогы /Random-KK /Екі итератор туралы әңгіме: Java-дағы бәсекеге қабілетті ...

Екі итератор туралы әңгіме: Java-дағы бәсекеге қабілетті модификация стратегиялары

Топта жарияланған
Жазбаның авторы - Краковтан (Польша) бағдарламалық жасақтама жасаушы Гжегож Мирек. Ол Java-да шамамен 6 жыл бұрын университетте оқып жүргенде дамыды және сол уақыттан бері ол осы саладағы дағдыларын жалықпай жылтыратып келеді. Ол әсіресе JVM өнімділігі мен оңтайландыруына қызығушылық танытады, ол негізінен блогында бұл туралы жазады .
Екі итератор туралы әңгіме: Java-дағы бәсекеге қабілетті модификация стратегиялары - 1
Ең танымал 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 жібермейді
  • Оларға итератор дәл бір рет жасалған кезде бар элементтерді айналып өтуге кепілдік беріледі және кейінгі өзгертулерді көрсете алады (бірақ талап етілмейді).

Сурет

Бұл стратегиямен итератор жинақтың жасалу сәтіндегі күйімен байланысты – бұл жинақтың суреті. Бастапқы жинаққа енгізілген кез келген өзгертулер негізгі деректер құрылымының жаңа нұсқасын жасауға әкеледі. Бұл біздің суретті өзгеріссіз қалдырады, сондықтан ол итератор жасалғаннан кейін орын алған жинақтағы өзгерістерді көрсетпейді. Бұл жақсы ескі көшіру бойынша жазу (COW) әдісі . Ол бір мезгілде өзгертулер мәселесін толығымен шешеді, сондықтан ConcurrentModificationException бұл тәсілмен жасалмайды. Сонымен қатар, итераторлар элементтерді өзгертетін әрекеттерді қолдамайды. Жазу бойынша көшіру жинақтарын пайдалану әдетте тым қымбат болады, бірақ өзгертулер итератордың өтуіне қарағанда әлдеқайда жиі орын алса, оларды пайдалану мағынасы бар. Мысалдар CopyOnWriteArrayList және CopyOnWriteArraySet сыныптары болып табылады .

Анықталмаған мінез-құлық

Сіз Vector және Hashtable сияқты бұрынғы жинақ түрлерінде анықталмаған әрекетке тап болуыңыз мүмкін . Екеуінде де стандартты сәтсіз итераторлар бар, бірақ сонымен қатар олар Санақ интерфейсінің іске асырылуын пайдалануға мүмкіндік береді және олар бір мезгілде модификацияланған жағдайда өзін қалай ұстау керектігін білмейді. Сіз қайталанатын немесе жоқ кейбір элементтерді немесе тіпті кейбір ерекше ерекшеліктерді кездестіруіңіз мүмкін. Олармен ойнамаған дұрыс!
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION