Салом! Мо омӯзиши чанд риштаро идома дода истодаем ва имрӯз мо бо як калимаи нави калидӣ - усули volatile ва yield() шинос мешавем. Биёед бифаҳмем, ки ин чист :)
Калимаи калидӣ
Ҳангоми сохтани замимаҳои бисёр ришта мо метавонем бо ду мушкилоти ҷиддӣ рӯ ба рӯ шавем. Аввалан, ҳангоми кори як замимаи бисёрқабата, риштаҳои гуногун метавонанд қиматҳои тағирёбандаҳоро кэш кунанд (мо дар ин бора дар лексияи "Истифодаи ноустувор" бештар сӯҳбат хоҳем кард ). Мумкин аст, ки як ришта арзиши тағирёбандаро тағир диҳад, аммо дуввум ин тағиротро надид, зеро он бо нусхаи кэшшудаи тағирёбанда кор мекард. Табиист, ки оқибатҳо метавонанд ҷиддӣ бошанд. Тасаввур кунед, ки ин на танҳо як навъ "тағйирёбанда", балки барои мисол, тавозуни корти бонкии шумо, ки ногаҳон ба таври тасодуфӣ ба пешу пас ҷаҳида оғоз кард :) На он қадар гуворо, дуруст? Дуюм, дар Java, амалиёти хондан ва навиштанро дар ҳама гуна майдонҳо, ба истисноиlong
ва double
атомӣ. Атомӣ чист? Хуб, масалан, агар шумо арзиши як тағирёбандаро дар як ришта тағир диҳед int
ва дар риштаи дигар арзиши ин тағирёбандаро хонед, шумо ё арзиши кӯҳнаи онро мегиред ё арзиши навро, ки пас аз тағир додани он пайдо шуд риштаи 1. Дар он ҷо ягон "имконоти мобайнӣ" пайдо намешавад Шояд. Аммо, ин бо long
ва double
кор намекунад . Чаро? Зеро он кросс-платформа аст. Оё шумо дар хотир доред, ки чӣ тавр мо дар сатҳи аввал гуфта будем, ки принсипи Java "як бор навишта мешавад, дар ҳама ҷо кор мекунад"? Ин кросс-платформа аст. Яъне, барномаи Java дар платформаҳои тамоман дигар кор мекунад. Масалан, дар системаҳои оператсионии Windows, versionҳои гуногуни Linux ё MacOS ва дар ҳама ҷо ин барнома устувор кор мекунад. long
ва double
- примитивҳои аз ҳама "вазнин" дар Java: вазнашон 64 бит. Ва баъзе платформаҳои 32-битӣ атомии хондан ва навиштани тағирёбандаҳои 64-битиро иҷро намекунанд. Чунин тағирёбандаҳо дар ду амал хонда ва навишта мешаванд. Аввалан, 32 битҳои аввал ба тағирёбанда навишта мешаванд, баъд 32 бит. Мувофиқи ин, дар ин мавридҳо мушкилот пайдо шуданаш мумкин аст. Як ришта арзиши 64-битро ба тағирёбанда менависадХ
, ва вай ин корро «дар ду қадам» мекунад. Дар айни замон, риштаи дуюм кӯшиш мекунад, ки арзиши ин тағирёбандаро бихонад ва онро дуруст дар мобайн иҷро мекунад, вақте ки 32 битҳои аввал аллакай навишта шудаанд, вале дуюмашон ҳанӯз навишта нашудаанд. Дар натиҷа, он арзиши фосилавӣ ва нодурустро мехонад ва хатогӣ ба амал меояд. Масалан, агар дар чунин платформа мо кӯшиш кунем, ки рақамро ба тағирёбанда нависем - 9223372036854775809 - он 64 битро ишғол мекунад. In binary form it will look like this: 100000000000000000000000000000000000000000000000000000000000000001 The first thread will start writing this number to a variable, and will first write the first 32 bits: 1000000000000000000000000000 00000 and then the second 32: 00000000000000000000000000000001 And a second thread can wedge into this gap and арзиши фосилавии тағирёбандаро хонед - 1000000000000000000000000000000000, 32 битҳои аввал, ки аллакай навишта шудаанд. Дар системаи даҳӣ ин адад ба 2147483648 баробар аст. Яъне мо танҳо мехостем рақами 9223372036854775809-ро ба тағирёбанда нависем, аммо аз сабаби он ки ин амалиёт дар баъзе платформаҳо атомӣ нест, мо рақами “чап”-ро гирифтем 2147483648 , ки ба мо лозим нест, аз кучо. ва маълум нест, ки он ба кори барнома чй гуна таъсир мерасонад. Риштаи дуюм танҳо арзиши тағирёбандаро пеш аз навиштани он хонд, яъне 32 битҳои аввалро дид, аммо 32 битҳои дуюмро не. Ин мушкилот, албатта, дирӯз ба вуҷуд наомадаанд ва дар Java онҳо танҳо бо истифода аз як калимаи калидӣ ҳал карда мешаванд - volatile . Агар мо дар барномаи худ ягон тағирёбандаро бо калимаи ноустувор эълон кунем...
public class Main {
public volatile long x = 2222222222222222222L;
public static void main(String[] args) {
}
}
... ин маънои онро дорад:
- Он ҳамеша ба таври атомӣ хонда ва навишта мешавад. Ҳатто агар он 64-бит
double
ёlong
. - Мошини Java онро кэш намекунад. Ҳамин тавр, вазъияте, ки 10 ришта бо нусхаҳои маҳаллии худ кор мекунад, истисно карда мешавад.
Усули yield ().
Мо аллакай бисёр усулҳои синфро дида баромадемThread
, аммо як чизи муҳиме ҳаст, ки барои шумо нав хоҳад буд. Ин усули yield() аст . Аз инглисӣ ҳамчун "додан" тарҷума шудааст. Ва ин маҳз ҳамон чизест, ки усул кор мекунад! Вақте ки мо усули ҳосилхезиро дар ришта меномем, он воқеан ба риштаҳои дигар мегӯяд: "Хуб, бачаҳо, ман саросема нестам, бинобар ин, агар барои касе аз шумо гирифтани вақти CPU муҳим бошад, онро бигиред, ман таъҷилӣ нест." Ин як мисоли оддии он аст, ки чӣ тавр кор мекунад:
public class ThreadExample extends Thread {
public ThreadExample() {
this.start();
}
public void run() {
System.out.println(Thread.currentThread().getName() + "give way to others");
Thread.yield();
System.out.println(Thread.currentThread().getName() + " has finished executing.");
}
public static void main(String[] args) {
new ThreadExample();
new ThreadExample();
new ThreadExample();
}
}
Мо пай дар пай се ришта - Thread-0
, Thread-1
ва Thread-2
. Thread-0
аввал сар мешавад ва дархол ба дигарон рох медихад. Пас аз он оғоз меёбад Thread-1
, ва инчунин роҳ медиҳад. Пас аз он, он оғоз меёбад Thread-2
, ки он ҳам пасттар аст. Мо дигар ришта надорем ва пас аз он ки Thread-2
риштаи охирин аз ҷои худ даст кашид, нақшакаш назар мекунад: «Пас, дигар риштаҳои нав нест, мо дар навбат кӣ ҳастем? Кӣ охирин бор пештар ҷои худро дод Thread-2
? Ман фикр мекунам он буд Thread-1
? Хуб, бигзор он иҷро шавад." Thread-1
кори худро то охир ичро мекунад, баъд аз он планкаш риштаро координация мекунад: «Хуб, ришта-1 ба охир расид. Оё мо ягон каси дигар дорем? ” Дар навбат Thread-0 мавҷуд аст: он фавран пеш аз Thread-1 ҷои худро дод. Холо кор ба сари у расида, то охир ичро карда мешавад. Пас аз он нақшасоз ҳамоҳангсозии риштаҳоро анҷом медиҳад: "Хуб, Thread-2, шумо ба риштаҳои дигар роҳ додед, онҳо аллакай кор кардаанд. Шумо охирин касе будед, ки роҳ додед, акнун навбати шумост.” Пас аз ин, Thread-2 ба анҷом мерасад. Натиҷаи консол чунин хоҳад буд: Thread-0 ба дигарон ҷой медиҳад Thread-1 ба дигарон ҷой медиҳад Thread-2 ба дигарон медиҳад Thread-1 иҷроишро анҷом дод. Thread-0 иҷроишро анҷом дод. Thread-2 иҷроишро анҷом дод. Барномасози ришта, албатта, метавонад риштаҳоро бо тартиби дигар иҷро кунад (масалан, 2-1-0 ба ҷои 0-1-2), аммо принсип як аст.
Пеш аз қоидаҳо рӯй медиҳад
Охирин чизе, ки мо имрӯз ба он муроҷиат хоҳем кард, ин принсипҳои " пеш аз рӯй медиҳад " аст. Тавре ки шумо аллакай медонед, дар Java, қисми зиёди кори ҷудо кардани вақт ва захираҳо ба риштаҳо барои анҷом додани вазифаҳои онҳо аз ҷониби нақшаи ришта анҷом дода мешавад. Инчунин, шумо зиёда аз як маротиба дидаед, ки чӣ гуна риштаҳо бо тартиби худсарона иҷро мешаванд ва аксар вақт пешгӯии он ғайриимкон аст. Ва дар маҷмӯъ, пас аз барномасозии "пайвандӣ", ки мо қаблан анҷом дода будем, чанд ришта ба як чизи тасодуфӣ монанд аст. Тавре ки шумо аллакай дидед, пешрафти як барномаи бисёрҷабҳаро метавон бо истифода аз маҷмӯи тамоми усулҳо идора кард. Аммо илова бар ин, дар Java multithreading боз як "ҷазираи устуворӣ" мавҷуд аст - 4 қоида бо номи " рӯй медиҳад-пеш ". Айнан аз забони англисӣ ин ҳамчун "пеш аз рӯй медиҳад" ё "пеш аз он рӯй медиҳад" тарҷума шудааст. Маънои ин қоидаҳоро фаҳмидан хеле осон аст. Тасаввур кунед, ки мо ду ришта дорем -A
ва B
. Ҳар яке аз ин риштаҳо метавонанд амалҳо 1
ва 2
. Ва ҳангоме ки дар ҳар як қоида мо мегӯем " А рӯй медиҳад-пеш аз В " ин маънои онро дорад, ки ҳамаи тағиротҳои ришта A
пеш аз амалиёт 1
ва тағироте, ки ин амалиёт ба он овардааст, B
дар вақти анҷом додани амалиёт ба ришта намоён аст 2
ва пас аз анҷом додани амалиёт. Ҳар яке аз ин қоидаҳо кафолат медиҳад, ки ҳангоми навиштани барномаи бисёрсабҳа баъзе рӯйдодҳо 100% пеш аз дигарон рӯй медиҳанд ва ришта B
дар вақти амалиёт 2
ҳамеша аз тағироте, ки ришта А
ҳангоми амалиёт анҷом додааст, огоҳ хоҳад буд. 1
. Биёед ба онҳо назар андозем.
Қоидаи 1.
Баровардани мутекс пеш аз он ки риштаи дигар ҳамон мониторро ба даст орад, рух медиҳад. Хуб, дар ин ҷо ҳама чиз равшан ба назар мерасад. Агар мутекси an object ё синф бо як ришта ба даст оварда шавад, масалан, риштаА
, риштаи дигар (thread B
) дар як вақт онро ба даст оварда наметавонад. Шумо бояд то он даме, ки mutex озод карда шавад, интизор шавед.
Қоидаи 2.
Thread.start()
Ин пеш аз усул рӯй медиҳад Thread.run()
. Ҳеҷ чиз мураккаб ҳам нест. Шумо аллакай медонед: барои он ки code дар дохor метод иҷро шавад run()
, шумо бояд усулро дар ришта даъват кунед start()
. Ин аз они аст, на худи усул run()
! Ин қоида кафолат медиҳад, ки Thread.start()
арзишҳои ҳама тағирёбандаҳои пеш аз иҷро муқарраршуда дар дохor усуле, ки ба иҷро оғоз кардаанд, намоён хоҳанд шуд run()
.
Қоидаи 3.
Анҷоми усулrun()
пеш аз баромадани усул сурат мегирад join()
. Биёед ба ду ҷараёнамон баргардем - А
ва B
. Мо усулро join()
тавре меномем, ки ришта B
бояд то анҷоми A
кораш интизор шавад. Ин маънои онро дорад, ки усули run()
an objectи А, бешубҳа, то охир кор хоҳад кард. Ва ҳама тағирот дар маълумоте, ки дар усули run()
ришта ба амал меоянд A
, дар ришта B
ҳангоми интизории анҷомёбӣ A
ва худ ба кор шурӯъ мекунанд, комилан намоён хоҳанд шуд.
Қоидаи 4.
Навиштан ба тағирёбандаи тағйирёбанда пеш аз хондан аз ҳамон тағирёбанда сурат мегирад . Бо истифода аз калимаи калидӣ, мо воқеан ҳамеша арзиши ҷориро мегирем. Хатто дар мавридиlong
ва double
, проблемахое, ки пештар бо онхо сухан рафт. Тавре ки шумо аллакай фаҳмед, тағирот дар баъзе риштаҳо на ҳама вақт ба риштаҳои дигар намоён мешаванд. Аммо, албатта, аксар вақт ҳолатҳое ҳастанд, ки чунин рафтори барнома ба мо мувофиқат намекунад. Фарз мекунем, ки мо ба тағирёбанда дар ришта арзиш таъин кардем A
:
int z;
….
z= 555;
Агар риштаи мо B
арзиши тағирёбандаро z
ба консол чоп мекард, он метавонад ба осонӣ 0-ро чоп кунад, зеро вай дар бораи арзиши ба он таъиншуда хабар надорад. Ҳамин тавр, Қоидаи 4 ба мо кафолат медиҳад: агар шумо тағирёбандаро z
ноустувор эълон кунед, тағирот ба арзишҳои он дар як ришта ҳамеша дар риштаи дигар намоён хоҳад буд. Агар мо калимаи ноустуворро ба рамзи қаблӣ илова кунем...
volatile int z;
….
z= 555;
...вазъияте, ки ҷараён B
0 ба консол мебарорад, истисно карда мешавад. Навиштан ба тағирёбандаҳои тағйирёбанда пеш аз хондан аз онҳо сурат мегирад.
GO TO FULL VERSION