Бисёрмаҷрии дар Java
Java Virtual Machine ҳисобҳои параллелӣ-ро дастгирӣ мекунад. Ҳама ҳисобҳо метавонанд дар контексти як ё якчанд маҷрҳо иҷро шавад. Мо осонан ба як ресурс ё объект барои якчанд маҷрҳо дастрасӣ кардан мумкин аст, ҳамчунин метавонем маҷрро ба иҷро намудани блоки алоҳидаи код танзим кунем.
Ҳар як таҳиягар бояд ҳамкорӣ бо маҷрҳоро ҳангоми амалиёти хондан ва навиштан барои ресурсҳое, ки ба якчанд маҷрҳо ҷудо карда шудаанд, ҳамоҳанг кунад.
Муҳим аст, ки ҳангоми муроҷиат ба ресурс дар ихтиёри шумо маълумоти актуал бошад, то дигар маҷр онҳоро тағир дода ва шумо маълумоти навтаринро гиред. Ҳатто агар банди мисолро гирем, то ба он пулҳо наомадаанд, шумо наметавонед онҳоро истифода баред, бинобар ин муҳим аст, ки ҳамеша маълумоти актуал дошта бошед. Дар Java классҳои махсус барои ҳамоҳангсозии маҷрҳо ва идора намудани онҳо вуҷуд доранд.
Объектҳои маҷрхонаҳо
Ҳама аз маҷри асосӣ сар мешавад, яъне дар барномаи шумо аллакай як маҷри иҷрошаванда вуҷуд дорад. Маҷри асосӣ метавонад маҷрҳои дигарро бо кӯмаки Callable ё Runnable эҷод кунад. Эҷодкунӣ танҳо бо натиҷаи баргашт гуногун мешавад, Runnable натиҷа намедиҳад ва наметавонад истисноҳои расмиро партояд. Аз ин рӯ, шумо имконияти хубе барои сохтани кори самарабахш бо файлҳо доред, аммо ин хеле хатарнок аст ва бояд эҳтиёткор бошед.
Инчунин имконияти ба кор даровардани маҷр дар ядрои алоҳидаи протсессори марказӣ вуҷуд дорад. Система метавонад осонан байни маҷрҳо кӯчад ва иҷрои маҷри муайянро бо танзимоти дуруст иҷро кунад: яъне аввал маҷре иҷро мешавад, ки маълумотҳоро мехонад, ҳангоме ки маълумотҳо дорем, ба маҷре, ки барои санҷиш масъул аст, медиҳем, пас аз ин барои иҷрои баъзе мантиқҳои тиҷоратӣ ба маҷри дигар медиҳем ва бо маҷри нав онҳоро боз навишта мекунем. Дар чунин ҳолатҳо 4 маҷр як ба як маълумотҳоро коркард мекунанд ва ҳамаи он тезтар аз як маҷр кор мекунад. Ҳар як чунин маҷр ба маҷри нативи ОС табдил меёбад, ва усули табдилоти он аз амалисозии JVM вобаста аст.
Класси Thread барои эҷоди маҷрҳо ва кор бо онҳо хизмат мекунад. Дар он механизмҳои стандартии идоракунӣ мавҷуданд, инчунин абстрактӣ, масалан, классҳо ва коллексияҳо аз java.util.concurrent.
Синхронизатсияи маҷрҳо дар Java
Муошират бо тақсими дастрасӣ ба объектҳо таъмин карда мешавад. Ин хеле самаранок аст, вале дар айни замон осонан хатоги кардан мумкин аст. Хатогиҳо ду намуди мутлақи доран: халалдоршавии маҷрҳо - вақте ки маҷри дигар ба маҷри шумо дахолат мекунад ва хатогиҳои мутлақиятӣ дар хотираи - консистентности памяти. Барои ҳалли ин хатогиҳо ва пешгирӣ аз онҳо мо усулҳои гуногуни синхронизатсия дорем.
Мо бо ҳамоҳангсозии маҷрҳо дар Java бо мониторҳо машғулем, ки ин як механизми сатҳи баланди имкон аст, ки танҳо як маҷрро маҳсулоти кодро бо ин монитор муҳофизат мекунад, иҷро кунад. Рафтори мониторҳо дар шартномаҳои бастакунӣ баррасӣ мешавад; як монитор - як бастакунӣ.
Синхронизатсия якчанд лаҳзаҳои муҳими дошта, ки ба онҳо бояд диққат диҳед. Лаҳзаи аввал - ин истиснои мутақобили (mutual exclusion) - танҳо як маҷр метавонад мониторро дошта бошад, пас синхронизатсия дар монитор маънои онро дорад, ки ҳангоме ки як маҷр ба блоки synchronized медарояд, ки бо монитор муҳофизат шудааст, ҳеҷ маҷри дигар наметавонад ба блоки, ки бо ин монитор муҳофизат шуда, дарояд, то ки маҷри аввал аз блоки synchronized набарояд. Яъне якчанд маҷрҳо наметавонанд ба як блоки synchronized дар як вақт муроҷиат кунанд.
Аммо синхронизатсия танҳо истиснои мутақобил нест. Синхронизатсия кафолат медиҳад, ки маълумоте, ки пеш аз ё дар дохили блоки синхронизатсияшуда ба хотира навишта шудааст, барои дигар маҷрҳое, ки бо ин монитор ҳамоҳангсозӣ шудаанд, намоён мешавад. Пас аз баромадан аз блок, мо мониторро озод мекунем ва маҷри дигар метавонад онро гирифта ва ин блоки кодро иҷро кунад.
Ҳангоме ки маҷри нав мониторро мегирад, мо ба ин блоки код дастрасшавӣ ва имконият дорем, ва дар ин вақт тағирёбандаҳо аз хотираи асосӣ бор карда мешаванд. Пас мо ҳама сабтҳои кардашударо, ки қаблан бо озодӣ (release) аз монитори дигар кард шуда буд, мебинем.
Хондан-навиштан дар майдон - амалиёти атомист, агар майдон бо volatile эълон шудааст, ё муҳофизат карда шуда бошад бо бастакунӣ, ки пеш аз ҳар хондан-навиштан гирифта мешавад. Аммо агар шумо бо хатогӣ рӯ ба рӯ шавед, хатои бозсозӣ (тағйири тартиби иҷро, reordering) ёбед. Он дар барномаҳои бисёрмаҷрии номутобиқ синхронизатсияшуда намоён мешавад, ки дар он як маҷр метавонад таъсироти, ки тавассути маҷрҳои дигар истеҳсол шудаанд, мушоҳида кунад.Таъсири истиснои мутақобил ва синхронизатсияи маҷрҳо, яъне кори муносиби онҳо танҳо бо вуруди ба блоки synchronized ё метод, ки блоккунии номаълум мегирад ё гирифтани блоккунии ба таври возеҳ таъмин карда мешавад. Мо дар бораи ин поёнтар сӯҳбат мекунем. Ҳарду роҳҳои корӣ ба хотираи шумо таъсир мекунанд ва муҳим аст, ки кор бо volatile-тағирёбандаҳоро фаромӯш накунед.
Вилоятҳои Volatile дар Java
Агар тағирёбанда бо volatile нишон дода шудааст, он глобалӣ дастрас аст. Ин маънои онро дорад, ки агар маҷр ба тағирёандаи volatile муроҷиат кунад, он арзиши онро пеш аз он ки арзишро аз кеш истифода барад, мегирад.
Навиштан ҳамчун озодкунии монитор кор мекунад ва хондан ҳамчун гирифтани монитор. Дастрасӣ дар нисбати намуди “пештар иҷро мешавад” амалӣ мегардад. Агар бифаҳмем, ки ҳамаи он чизе ки барои маҷри A намоён шуда буд, ҳангоме ки он ба тағирёандаи volatile муроҷиат кард, ин барои маҷри B низ намоён мешавад. Яъне шумо кафолат дода шуда метавонед, ки тағиротҳои худро дар дигар маҷҳо аз даст надиҳед.
Volatile-тағирёбандаҳо атомиянд, яъне ҳангоми хондани чунин тағирёбандаҳо чунин таъсир истифода мешавад, ҳамчун гирифтани блоккунӣ - маълумотҳо дар хотира эълон шудаанд, ё номуайян мебошанд ва арзиши тағирёбандаи volatile аз хотира дубора хонда мешавад. Ҳангоми навиштан таъсири барои хотира истифода мешавад, ҳамчун озодкунии блоккунӣ - майдони volatile ба хотира навишта мешавад.
Java Concurrent
Агар шумо хоҳед, ки барномаи бисёрмаҷрии самарабахш созед, лозим аст, ки классҳои аз библиотекаи JavaConcurrent, ки дар пакети java.util.concurrent ҷойгир шудаанд, истифода баред.
Библиотека хеле васеъ аст ва функсионалҳои мухталиф дорад, бинобар ин биёед бубинем, ки дохили он чӣ мавҷуд аст ва ба баъзе модулҳо тақсим кунем:
Concurrent Collections — маҷмӯи коллексияҳо барои кор дар муҳити бисёрмаҷрӣ. Ба ҷои оберткаи асосӣ Collections.synchronizedList бо бастани дастрасӣ ба коллексияи тамоми аз бастакунҳо дар сегментҳои маълумотӣ истифода баред ё алгоритмҳои бе интизорӣ барои хондани параллели маълумот истифода баред.
Queues — навбатҳои бе бастасанҷанда ва бастасанҷанда барои кор дар муҳити бисёрмаҷрӣ. Навбатҳои бе бастасанҷанда ба суръат ва кор бе бастанки маҷрҳо тамаркуз мекунанд. Навбатҳои бастасанҷанда барои кор мувофиқанд, вақте ки бояд маҷрҳо Producer ё Consumer-ро "суст" кунед. Масалан, дар он ҳолат, ки баъзе шароитҳо анҷом наёфтаанд, навбат холӣ ё пурра аст, ё Consumer озод нест.
Synchronizers — утилитҳои иловагӣ барои синхронизатсияи маҷрҳо. Онҳо ҳамчун аслиҳаи пурқувват дар ҳисобҳои "параллелӣ" амал мекунанд.
Executors — фреймворк барои эҷоди осони ҳавзҳои маҷрҳо, осонан танзим кардани нақшаи кории вазифаҳои асинхронӣ бо гирифтани натиҷаҳоро осон мекунад.
Locks — механизмҳои ҷолибии синхронизатсияи маҷрҳо нисбат ба synchronized, wait, notify, notifyAll асосӣ.
Atomics — классҳое, ки метавонанд амалиёти атомӣ дар болои примитивҳо ва ишораҳоро дастгирӣ кунанд.
GO TO FULL VERSION