JavaRush /Java блогу /Random-KY /Эки итератордун жомогу: Javaдагы атаандаштык модификациял...

Эки итератордун жомогу: Javaдагы атаандаштык модификациялоо стратегиялары

Группада жарыяланган
Билдирүүнүн автору Краковдон (Польша) программалык камсыздоону иштеп чыгуучу Гжегож Мирек. Ал Явада 6 жылдай мурун, университетте окуп жүргөндө эле өнүгүп баштаган жана ошондон бери ал бул жааттагы чеберчorгин талыкпастан жылмалоодо. Ал өзгөчө JVM иштешине жана оптималдаштырууга кызыкдар, бул тууралуу ал негизинен өзүнүн блогунда жазат .
Эки итератордун жомогу: Javaдагы атаандаштык модификация стратегиялары - 1
Эң популярдуу Java интервью суроолорунун айрымдары төмөнкүлөрдү камтыйт: Иштебей турган тез жана коопсуз итераторлордун ортосунда кандай айырма бар? Буга эң жөнөкөйлөштүрүлгөн жооп: Итерация учурунда коллекция өзгөрбөсө, катасыз тез итератор ConcurrentModificationException ыргытат, бирок катасыз итератор андай эмес. Бул абдан маңыздуу угулат, бирок, интервьюер ийгorксиз деп эмнени айткысы түшүнүксүз бойдон калууда? Java тorнин спецификациялары бул терминди итераторлорго карата аныктаbyte. Бирок, төрт атаандаштык өзгөртүү стратегиясы бар.

Конкурстук өзгөртүү

Биринчиден, атаандаштык (же параллелдүү) модификация деген эмне экенин аныктап көрөлү. Айталы, бизде коллекция бар жана итератор активдүү болгондо, бул итератордон келбеген кээ бир өзгөрүүлөр болот. Бул учурда, биз атаандаштык модификациясын алабыз. Мен сизге жөнөкөй мисал келтирейин: бизде бир нече жип бар дейли. Биринчи жип итерацияланат, ал эми экинчи жип бир эле коллекциянын элементтерин киргизет же алып салат. Бирок, биз бир жиптүү чөйрөдө иштеп жатканда 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

Ийгorксиз

Жогорудагы code фрагменти катасыз тез итератордун мисалы болуп саналат . Көрүнүп тургандай, итератордон экинчи элементти алууга аракет кылып жатканда ConcurrentModificationException ыргытылган . Итератор коллекция түзүлгөндөн бери өзгөртүлгөнүн кайдан билет? Мисалы, коллекцияда дата/убакыт белгиси болушу мүмкүн, айталы, lastModified . Итератор түзүүдө бул талааны көчүрүп, аны итератор an objectинде сактоо керек. Андан кийин, кийинки() методу чакырылган сайын , сиз коллекциядагы lastModified маанисин итератордун көчүрмөсү менен салыштырып турасыз . Абдан окшош ыкма, мисалы, ArrayList классын ишке ашырууда колдонулат . Анда тизме канча жолу өзгөртүлгөнүн сактаган modCount инстанция өзгөрмөсү бар :
final void checkForComodification() {
   if (modCount != expectedModCount)
       throw new ConcurrentModificationException();
}
Белгилей кетчү нерсе, ийгorксиз итераторлор эң мыкты породада иштешет, башкача айтканда, ConcurrentModificationException бир эле учурда модификацияланган учурда ыргытылат деген кепилдик жок. Андыктан аларга ишенбешиңиз керек, тескерисинче, алар каталарды аныктоо үчүн колдонулушу керек. Кошумча эмес коллекциялар катасыз тез итераторлорду камсыз кылат.

Алсыз ырааттуулук

Java.util.concurrent топтомундагы көпчүлүк параллелдүү коллекциялар (мисалы, ConcurrentHashMap жана көпчүлүк кезекте ) начар ырааттуу итераторлорду камсыз кылат. Бул терминдин мааниси documentтерде абдан жакшы түшүндүрүлгөн :
  • Алар башка операциялар менен бир убакта иштетorши мүмкүн
  • Алар эч качан ConcurrentModificationException ыргытышпайт
  • Алар итератор так бир жолу түзүлгөн учурда болгон элементтерди басып өтүүгө кепилдик берилет жана кийинки өзгөртүүлөрдү чагылдыра алат (бирок талап кылынbyte).

Снапшот

Бул стратегиянын жардамы менен, итератор коллекцияны түзүү учурундагы абалы менен байланышкан - бул коллекциянын сүрөтү. Баштапкы коллекцияга киргизилген ар кандай өзгөртүүлөр негизги маалымат структурасынын жаңы versionсын түзүүгө алып келет. Бул биздин сүрөттү өзгөртүүсүз калтырат, андыктан ал итератор түзүлгөндөн кийин болгон коллекциядагы өзгөрүүлөрдү чагылдырbyte. Бул жакшы эски көчүрмөнү жазуу (COW) техникасы . Ал толугу менен бир убакта өзгөртүү маселесин чечет, ошондуктан бул ыкма менен ConcurrentModificationException түзүлбөйт. Кошумчалай кетсек, итераторлор элементтерди өзгөрткөн операцияларды колдобойт. Жазууга көчүрүү жыйнактары колдонуу үчүн өтө кымбатка турат, бирок өзгөртүүлөр итератордун өтүүсүнө караганда алда канча азыраак болуп турса, аларды колдонуунун мааниси бар. Мисалдар CopyOnWriteArrayList жана CopyOnWriteArraySet класстары .

Белгисиз жүрүм-турум

Vector жана Hashtable сыяктуу эски коллекция түрлөрүндө аныкталбаган жүрүм-турумга туш болушуңуз мүмкүн . Экөөнүн тең стандарттуу иштебей турган итераторлору бар, бирок андан тышкары, алар Санактоо интерфейсинин ишке ашырылышын колдонууга мүмкүндүк берет жана бир эле учурда модификацияланган учурда өзүн кандай алып жүрүүнү бorшпейт. Кээ бир элементтердин кайталанып же жок болушуна, ал тургай кээ бир кызыктай өзгөчөлүктөргө туш болушуңуз мүмкүн. Алар менен ойнобой эле койгон жакшы!
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION