Multithreading sa Java

Ang Java Virtual Machine ay sumusuporta sa parallel computing . Ang lahat ng mga kalkulasyon ay maaaring isagawa sa konteksto ng isa o higit pang mga thread. Madali kaming makakapag-set up ng access sa parehong mapagkukunan o bagay para sa maraming mga thread, pati na rin mag-set up ng isang thread upang magsagawa ng isang solong bloke ng code.

Kailangang i-synchronize ng sinumang developer ang trabaho sa mga thread sa panahon ng read and write operations para sa mga resource na maraming thread na nakalaan sa kanila.

Mahalaga na sa oras ng pag-access sa mapagkukunan ay mayroon kang up-to-date na data upang mabago ito ng isa pang thread at makuha mo ang pinakabagong impormasyon. Kahit na kunin natin ang halimbawa ng isang bank account, hanggang sa dumating ang pera, hindi mo ito magagamit, kaya mahalaga na laging may up-to-date na data. Ang Java ay may mga espesyal na klase para sa pag-synchronize at pamamahala ng mga thread.

Mga bagay sa thread

Nagsisimula ang lahat sa pangunahing (pangunahing) thread, iyon ay, kahit man lang ang iyong programa ay mayroon nang isang tumatakbong thread. Ang pangunahing thread ay maaaring lumikha ng iba pang mga thread gamit ang Callable o Runnable . Ang paglikha ay naiiba lamang sa resulta ng pagbabalik, ang Runnable ay hindi nagbabalik ng isang resulta at hindi maaaring magtapon ng isang naka-check na exception. Samakatuwid, makakakuha ka ng isang magandang pagkakataon upang bumuo ng mahusay na trabaho sa mga file, ngunit ito ay lubhang mapanganib at kailangan mong mag-ingat.

Posible ring mag-iskedyul ng thread execution sa isang hiwalay na CPU core. Ang system ay madaling lumipat sa pagitan ng mga thread at magsagawa ng isang partikular na thread na may tamang mga setting: iyon ay, ang thread na nagbabasa ng data ay unang pinaandar, sa sandaling mayroon kaming data, pagkatapos ay ipinapasa namin ito sa thread na responsable para sa pagpapatunay, pagkatapos nito ay ipinapasa namin ito sa thread upang maisagawa ang ilang pagkatapos ay lohika ng negosyo at isang bagong thread na isulat ang mga ito pabalik. Sa ganoong sitwasyon, 4 na thread ang nagpoproseso ng data sa turn at lahat ay gagana nang mas mabilis kaysa sa isang thread. Ang bawat naturang stream ay kino-convert sa isang native na stream ng OS, ngunit kung paano ito mako-convert ay depende sa pagpapatupad ng JVM.

Ang klase ng Thread ay ginagamit upang lumikha at magtrabaho kasama ang mga thread. Mayroon itong mga karaniwang mekanismo ng kontrol, pati na rin ang mga abstract, tulad ng mga klase at koleksyon mula sa java.util.concurrent .

Pag-synchronize ng Thread sa Java

Ang komunikasyon ay ibinibigay sa pamamagitan ng pagbabahagi ng access sa mga bagay. Ito ay napaka-epektibo, ngunit sa parehong oras napakadaling magkamali kapag nagtatrabaho. Ang mga error ay dumating sa dalawang kaso: pagkagambala sa thread - kapag ang isa pang thread ay nakakasagabal sa iyong thread, at mga error sa pagkakapare-pareho ng memorya - pagkakapare-pareho ng memorya. Upang malutas at maiwasan ang mga error na ito, mayroon kaming iba't ibang paraan ng pag-synchronize.

Ang pag-synchronize ng thread sa Java ay pinangangasiwaan ng mga monitor, ito ay isang mataas na antas na mekanismo na nagpapahintulot lamang sa isang thread na magsagawa ng isang bloke ng code na protektado ng parehong monitor sa isang pagkakataon. Ang pag-uugali ng mga monitor ay isinasaalang-alang sa mga tuntunin ng mga kandado; isang monitor - isang lock.

Ang pag-synchronize ay may ilang mahahalagang punto na kailangan mong bigyang pansin. Ang unang punto ay mutual exclusion - isang thread lamang ang maaaring magmay-ari ng monitor, kaya ang pag-synchronize sa monitor ay nagpapahiwatig na kapag ang isang thread ay pumasok sa isang naka-synchronize na block na protektado ng monitor, walang ibang thread ang makakapasok sa block na protektado ng monitor. ang monitor na ito hanggang sa ang unang thread ay lumabas sa naka-synchronize na bloke. Ibig sabihin, hindi ma-access ng maraming thread ang parehong naka-synchronize na block nang sabay-sabay.

Ngunit ang pag-synchronize ay hindi lamang pagbubukod sa isa't isa. Tinitiyak ng pag-synchronize na ang data na nakasulat sa memorya bago o sa loob ng isang naka-synchronize na block ay makikita ng iba pang mga thread na naka-synchronize sa parehong monitor. Pagkatapos lumabas sa block, inilabas namin ang monitor at maaaring kunin ito ng isa pang thread at simulan ang pagpapatupad ng block ng code na ito.

Kapag nakuha ng isang bagong thread ang monitor, nagkakaroon tayo ng access at ang kakayahang isagawa ang block ng code na iyon, at sa puntong iyon ay mailo-load ang mga variable mula sa pangunahing memorya. Pagkatapos ay makikita natin ang lahat ng mga entry na ginawang nakikita ng nakaraang paglabas ng monitor.

Ang read-write sa isang field ay isang atomic operation kung ang field ay idineklara na pabagu-bago o protektado ng isang natatanging lock na nakuha bago ang anumang read-write. Ngunit kung nakatagpo ka pa rin ng isang error, magkakaroon ka ng isang error tungkol sa muling pag-aayos (pagbabago ng pagkakasunud-sunod, muling pag-aayos). Ito ay nagpapakita ng sarili sa hindi wastong naka-synchronize na mga multi-threaded na programa, kung saan ang isang thread ay maaaring obserbahan ang mga epekto na ginawa ng iba pang mga thread.

Ang epekto ng mutual na pagbubukod at pag-synchronize ng mga thread, iyon ay, ang kanilang tamang operasyon ay nakakamit lamang sa pamamagitan ng pagpasok ng isang naka-synchronize na bloke o paraan na tahasang nakakakuha ng lock, o sa pamamagitan ng tahasang pagkuha ng lock. Pag-uusapan natin ito sa ibaba. Ang parehong paraan ng pagtatrabaho ay nakakaapekto sa iyong memorya at mahalagang huwag kalimutan ang tungkol sa pagtatrabaho sa mga pabagu-bagong variable.

Mga pabagu-bagong patlang sa Java

Kung ang isang variable ay minarkahan na volatile , ito ay magagamit sa buong mundo. Nangangahulugan ito na kung ang isang thread ay nag-access ng isang pabagu-bago ng isip na variable, makukuha nito ang halaga nito bago gamitin ang halaga mula sa cache.

Gumagana ang isang pagsulat tulad ng isang release ng monitor, at ang isang pagbabasa ay gumagana tulad ng isang monitor capture. Ang pag-access ay isinasagawa sa isang kaugnayan ng uri na "ginanap bago". Kung malalaman mo ito, ang lahat na makikita sa thread A kapag na-access nito ang isang pabagu-bagong variable ay ang variable para sa thread B. Ibig sabihin, garantisadong hindi mawawala ang iyong mga pagbabago mula sa iba pang mga thread.

Ang mga variable na pabagu-bago ay atomic, iyon ay, kapag nagbabasa ng naturang variable, ang parehong epekto ay ginagamit tulad ng kapag nakakuha ng isang lock - ang data sa memorya ay ipinahayag na hindi wasto o hindi tama, at ang halaga ng pabagu-bagong variable ay muling binabasa mula sa memorya. Kapag nagsusulat, ang epekto sa memorya ay ginagamit, pati na rin kapag naglalabas ng isang lock - isang pabagu-bago ng isip na patlang ay nakasulat sa memorya.

Kasabay ng Java

Kung gusto mong gumawa ng super-efficient at multi-threaded na application, dapat mong gamitin ang mga klase mula sa JavaConcurrent library , na nasa java.util.concurrent package .

Ang library ay napakalaki at may iba't ibang pag-andar, kaya tingnan natin kung ano ang nasa loob at hatiin ito sa ilang mga module:

Kasabay ng Java

Ang Concurrent Collections ay isang hanay ng mga koleksyon para sa pagtatrabaho sa isang multi-threaded na kapaligiran. Sa halip na ang pangunahing wrapper na Collections.synchronizedList na may pagharang sa access sa buong koleksyon, ginagamit ang mga lock sa mga segment ng data o ginagamit ang mga algorithm na walang paghihintay para magbasa ng data nang magkatulad.

Mga Queue - hindi humaharang at humaharang sa mga pila para sa pagtatrabaho sa isang multi-threaded na kapaligiran. Ang mga hindi nakaharang na pila ay nakatuon sa bilis at pagpapatakbo nang hindi hinaharangan ang mga thread. Ang pagharang sa mga pila ay angkop para sa trabaho kapag kailangan mong "pabagalin" ang mga thread ng Producer o Consumer . Halimbawa, sa isang sitwasyon kung saan ang ilan sa mga kundisyon ay hindi natutugunan, ang pila ay walang laman o puno, o walang libreng Consumer 'a.

Ang mga synchronizer ay mga utility utility para sa pag-synchronize ng mga thread. Ang mga ito ay isang malakas na sandata sa "parallel" computing.

Ang mga tagapagpatupad ay isang balangkas para sa mas maginhawa at madaling paglikha ng mga thread pool, madaling i-set up ang pag-iiskedyul ng mga asynchronous na gawain sa pagkuha ng mga resulta.

Ang mga lock ay maraming nababaluktot na mekanismo ng pag-synchronize ng thread kumpara sa pangunahing naka-synchronize , wait , notify , notifyAll .

Ang atomics ay mga klase na maaaring suportahan ang mga pagpapatakbo ng atomic sa mga primitive at reference.