Hi! Kita terus sinau babagan multithreading. Dina iki kita bakal ngerti
Nalika kita nelpon
volatile
tembung kunci lan yield()
cara. Ayo nyilem :)
Tembung kunci sing molah malih
Nalika nggawe aplikasi multithreaded, kita bisa nemoni rong masalah serius. Kaping pisanan, nalika aplikasi multithreaded mlaku, benang sing beda-beda bisa nyimpen nilai-nilai variabel (kita wis ngomong babagan iki ing pawulangan kanthi irah-irahan 'Using volatile' ). Sampeyan bisa duwe kahanan ing ngendi siji thread ngganti nilai variabel, nanging thread kapindho ora weruh owah-owahan, amarga iku bisa digunakake karo salinan cache sawijining variabel. Alami, akibate bisa serius. Upaminipun punika dudu sembarang variabel lawas nanging rodo imbangan akun bank, kang dumadakan wiwit acak mlumpat munggah lan mudhun :) Sing ora muni kaya fun, tengen? Kapindho, ing Jawa, operasi maca lan nulis kabeh jinis primitif,long
double
, iku atom. Contone, yen sampeyan ngganti nilai variabel int
ing siji utas, lan ing thread liyane sampeyan maca nilai variabel kasebut, sampeyan bakal entuk nilai sing lawas utawa sing anyar, yaiku nilai sing diasilake saka owah-owahan kasebut. ing thread 1. Ora ana 'nilai penengah'. Nanging, iki ora bisa digunakake karo long
s lan double
s. Kenging punapa? Amarga dhukungan lintas-platform. Elingi ing tingkat wiwitan sing kita ujar yen prinsip pedoman basa Jawa yaiku 'nulis sepisan, mlayu ing endi wae'? Tegese dhukungan lintas platform. Ing tembung liyane, aplikasi Java mlaku ing kabeh platform beda. Contone, ing sistem operasi Windows, macem-macem versi Linux utawa MacOS. Iku bakal mbukak tanpa alangan ing kabeh mau. Bobot ing 64 bit,long
double
minangka primitif 'paling abot' ing Jawa. Lan platform 32-bit tartamtu mung ora ngetrapake maca lan nulis atom variabel 64-bit. Variabel kasebut diwaca lan ditulis ing rong operasi. Kaping pisanan, 32 bit pisanan ditulis menyang variabel, banjur 32 bit liyane ditulis. Akibaté, masalah bisa muncul. Siji thread nulis sawetara nilai 64-bit menyang X
variabel lan nindakake ing rong operasi. Ing wektu sing padha, utas kapindho nyoba maca nilai variabel kasebut lan nindakake ing antarane rong operasi kasebut - nalika 32 bit pisanan wis ditulis, nanging 32 bit kapindho ora. Akibaté, maca nilai penengah, salah, lan kita duwe bug. Contone, yen ing platform kasebut, kita nyoba nulis nomer kasebut menyang 9223372036854775809 kanggo variabel, iku bakal manggoni 64 bit. Ing wangun binar, katon kaya iki: 10000000000000000000000000000000000000000000000000000000001 Utas pisanan wiwit nulis angka menyang variabel. Wiwitane, kasebut nyerat 32 bit pisanan (100000000000000000000000000000000000000000000000000000000000000) banjur kaping 32 bit 32 (00000000000000000000000000001) Lan utas kapindho bisa diselehake ing antarane operasi kasebut, maca nilai penengah variabel (100000000000000000000000000000000), yaiku 32 bit pisanan sing wis ditulis. Ing sistem desimal, angka iki 2.147.483.648. Ing tembung liya, kita mung pengin nulis nomer 9223372036854775809 menyang variabel, nanging amarga operasi iki ora atom ing sawetara platform, kita duwe nomer ala 2,147,483,648, sing metu saka endi wae lan bakal duwe efek sing ora dingerteni. program. Utas kapindho mung maca nilai variabel sadurunge rampung ditulis, yaiku benang ndeleng 32 bit pisanan, nanging ora 32 bit kapindho. Mesthi, masalah iki ora muncul wingi. Jawa ngrampungake karo tembung kunci siji: volatile
. Yen kita nggunakakevolatile
tembung kunci nalika ngumumake sawetara variabel ing program kita…
public class Main {
public volatile long x = 2222222222222222222L;
public static void main(String[] args) {
}
}
… tegese:
- Bakal tansah diwaca lan ditulis kanthi atom. Malah yen iku 64-dicokot
double
utawalong
. - Mesin Java ora bakal cache. Dadi sampeyan ora bakal duwe kahanan ing ngendi 10 utas nggarap salinan lokal dhewe.
Metode yield().
Kita wis nliti akehThread
metode kelas, nanging ana sing penting sing bakal dadi anyar kanggo sampeyan. Iku yield()
cara . Lan nindakake persis apa jenenge! 
yield
cara ing thread, iku bener ngomong karo thread liyane: 'Hei, wong lanang. Aku ora ing sembarang utamané cepet-cepet menyang ngendi wae, dadi yen penting kanggo sapa wae sing njaluk wektu prosesor, njupuk - Aku bisa ngenteni. Punika conto prasaja babagan cara kerjane:
public class ThreadExample extends Thread {
public ThreadExample() {
this.start();
}
public void run() {
System.out.println(Thread.currentThread().getName() + " yields its place 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();
}
}
Kita nggawe lan miwiti telung utas kanthi urutan: Thread-0
, Thread-1
, lan Thread-2
. Thread-0
diwiwiti luwih dhisik lan langsung ngasilake liyane. Banjur Thread-1
diwiwiti lan uga ngasilake. Banjur Thread-2
diwiwiti, sing uga ngasilake. Kita wis ora duwe utas maneh, lan sawise Thread-2
menehi panggonan pungkasan, panjadwal thread ngandika, 'Hmm, ora ana maneh thread anyar. Sapa sing ana ing antrian? Sapa sing menehi panggonan sadurunge Thread-2
? Iku misale jek iku Thread-1
. Oke, tegese kita bakal nglilani. Thread-1
ngrampungake karyane banjur panjadwal thread nerusake koordinasi: 'Oke, Thread-1
rampung. Apa kita duwe wong liya ing antrian?'. Utas-0 ana ing antrian: wis ngasilake papan sadurungeThread-1
. Saiki entuk giliran lan mlaku nganti rampung. Banjur panjadwal rampung ngoordinasi utas: 'Oke, Thread-2
, sampeyan wis nyerah menyang utas liyane, lan kabeh wis rampung saiki. Sampeyan sing pungkasan ngasilake, mula saiki giliran sampeyan. Banjur Thread-2
mlaku nganti rampung. Output console bakal katon kaya iki: Utas-0 ngasilake papan kanggo wong liya. Utas-0 wis rampung dieksekusi. Utas-2 wis rampung dieksekusi. Mesthi, panjadwal thread bisa miwiti thread ing urutan beda (contone, 2-1-0 tinimbang 0-1-2), nanging prinsip tetep padha.
Mengkono-sadurunge aturan
Babagan pungkasan sing bakal kita demek dina iki yaiku konsep ' kedadeyan sadurunge '. Kaya sing wis sampeyan ngerteni, ing Jawa, panjadwal thread nindakake akeh karya sing melu nyedhiakke wektu lan sumber daya kanggo benang kanggo nindakake tugase. Sampeyan uga wis bola-bali ndeleng carane Utas dieksekusi ing urutan acak sing biasane ora bisa kanggo prédhiksi. Lan umume, sawise pemrograman 'sequential' sing ditindakake sadurunge, pemrograman multithreaded katon kaya acak. Sampeyan wis percaya yen sampeyan bisa nggunakake macem-macem cara kanggo ngontrol aliran program multithreaded. Nanging multithreading ing Jawa nduweni siji pilar maneh - aturan 4 ' kedadeyan-sadurunge '. Ngerteni aturan kasebut cukup prasaja. Mbayangno sing kita duwe loro Utas -A
lanB
. Saben utas iki bisa nindakake operasi 1
lan 2
. Ing saben aturan, nalika kita ngomong ' A kedaden-sadurunge B ', kita ateges kabeh owah-owahan sing digawe dening thread A
sadurunge operasi 1
lan owah-owahan asil saka operasi iki katon kanggo thread B
nalika operasi 2
dileksanakake lan sesampunipun. Saben aturan njamin yen sampeyan nulis program multithreaded, acara tartamtu bakal kelakon sadurunge liyane 100% wektu, lan ing wektu operasi 2
thread B
bakal tansah weruh saka owah-owahan sing thread A
digawe sak operasi 1
. Ayo dideleng.
Aturan 1.
Ngeculake mutex kedadeyan sadurunge monitor sing padha dituku dening benang liyane. Aku mikir sampeyan ngerti kabeh ing kene. Yen mutex obyek utawa kelas dipikolehi dening siji utas., Contone, dening threadA
, thread liyane (utas B
) ora bisa ndarbeni ing wektu sing padha. Sampeyan kudu ngenteni nganti mutex dirilis.
Aturan 2.
Thread.start()
Cara kasebut kedadeyan sadurunge Thread.run()
. Maneh, ora ana sing angel ing kene. Sampeyan wis ngerti yen kanggo miwiti mbukak kode ing run()
cara, sampeyan kudu nelpon start()
cara ing thread. Secara khusus, metode wiwitan, dudu run()
metode kasebut dhewe! Aturan iki mesthekake yen nilai kabeh variabel sing disetel sadurunge Thread.start()
diarani bakal katon ing run()
cara kasebut yen wis diwiwiti.
Aturan 3.
Pungkasan metoderun()
kedadeyan sadurunge bali saka join()
metode kasebut. Ayo bali menyang rong utas: A
lan B
. Kita nyebat join()
cara kasebut supaya utas B
dijamin ngenteni rampunge benang A
sadurunge nindakake pakaryan. Iki tegese cara obyek A run()
dijamin kanggo mbukak nganti pungkasan. Lan kabeh owah-owahan data sing kedadeyan ing run()
cara thread A
dijamin satus persen bakal katon ing thread B
sawise rampung ngenteni thread A
rampung karyane supaya bisa miwiti karya dhewe.
Aturan 4.
Nulis menyangvolatile
variabel kedadeyan sadurunge maca saka variabel sing padha. Nalika nggunakake volatile
tembung kunci, kita mesthi entuk nilai saiki. Malah karo long
utawa double
(kita ngandika sadurungé bab masalah sing bisa kelakon kene). Minangka sampeyan wis ngerti, owah-owahan sing digawe ing sawetara utas ora tansah katon ing utas liyane. Nanging, mesthi, ana kahanan sing kerep banget yen prilaku kasebut ora cocog karo kita. Upaminipun kita nemtokake nilai kanggo variabel ing utas A
:
int z;
….
z = 555;
Yen B
thread kita kudu nampilake nilai variabel z
ing console, bisa gampang nampilake 0, amarga ora ngerti babagan nilai sing ditugasake. Nanging Aturan 4 njamin yen kita nyatakake z
variabel kasebut minangka volatile
, banjur owah-owahan ing nilai ing siji thread bakal tansah katon ing thread liyane. Yen kita nambahake tembung volatile
menyang kode sadurunge ...
volatile int z;
….
z = 555;
... banjur kita nyegah kahanan ing ngendi thread B
bisa nampilake 0. Nulis kanggo volatile
variabel mengkono sadurunge maca saka wong-wong mau.
GO TO FULL VERSION