Tento mesiac Java 101 uzatvára sériu vlákien zameraním na skupiny vlákien, volatilitu, lokálne premenné vlákna, časovače a ThreadDeath
trieda.
Pochopenie vlákien Java - prečítajte si celú sériu
- Časť 1: Predstavujeme vlákna a spustiteľné súbory
- Časť 2: Synchronizácia vlákna
- Časť 3: Plánovanie vlákna, čakanie / upozornenie a prerušenie vlákna
- Časť 4: Skupiny vlákien, volatilita, miestne premenné vlákna, časovače a smrť vlákna
Skupiny vlákien
V programe sieťového servera jedno vlákno čaká na a prijíma požiadavky z klientských programov na vykonávanie napríklad databázových transakcií alebo zložitých výpočtov. Vlákno zvyčajne vytvorí nové vlákno na vybavenie žiadosti. V závislosti od objemu požiadavky môže byť súčasne prítomných veľa rôznych vlákien, čo komplikuje správu vlákien. Na zjednodušenie správy vlákien si programy organizujú svoje vlákna pomocou skupiny vlákien—java.lang.ThreadGroup
objekty, ktoré zoskupujú súvisiace vlákna ' Závit
(a Závit
podtrieda) objekty. Váš program môže napríklad použiť ThreadGroup
zoskupiť všetky tlačové vlákna do jednej skupiny.
Poznámka: Aby bola diskusia jednoduchá, odkazujem na skupiny vlákien, akoby organizovali vlákna. V skutočnosti sa skupiny vlákien organizujú Závit
(a Závit
podtrieda) objekty spojené s vláknami.
Java vyžaduje každé vlákno a každú skupinu vlákien - uložte skupinu koreňových vlákien, systém
- pripojiť sa k inej skupine vlákien. Toto usporiadanie vedie k hierarchickej štruktúre skupín vlákien, ktorú obrázok nižšie ilustruje v kontexte aplikácie.
V hornej časti štruktúry figúry je systém
skupina vlákien. Vytvorené JVM systém
skupina organizuje vlákna JVM, ktoré sa zaoberajú dokončovaním objektov a ďalšími systémovými úlohami, a slúži ako skupina koreňových vlákien v hierarchickej štruktúre skupín vlákien aplikácie. Rovno pod systém
je vytvorený JVM hlavný
skupina vlákien, ktorá je systém
skupina podvlákna (skrátene podskupina). hlavný
obsahuje najmenej jedno vlákno - hlavné vlákno vytvorené JVM, ktoré vykonáva pokyny v bajtovom kóde v hlavný()
metóda.
Pod hlavný
skupina býva podskupina 1
a podskupina 2
podskupiny, podskupiny vytvorené aplikáciou (ktoré aplikácia figúry vytvára). Ďalej podskupina 1
zoskupuje tri vlákna vytvorené aplikáciou: závit 1
, závit 2
a závit 3
. Naproti tomu podskupina 2
zoskupuje jedno vlákno vytvorené aplikáciou: moje vlákno
.
Teraz, keď už ovládate základné veci, začnime vytvárať skupiny vlákien.
Vytvorte skupiny vlákien a priraďte vlákna k týmto skupinám
The ThreadGroup
Dokumentácia triedy SDK odhaľuje dvoch konštruktérov: ThreadGroup (názov reťazca)
a ThreadGroup (ThreadGroup rodič, názov reťazca)
. Obaja konštruktéri vytvoria skupinu vlákien a pomenujú ju ako názov
parameter určuje. Konštruktéri sa líšia výberom toho, ktorá skupina vlákien slúži ako nadradená pre novovytvorenú skupinu vlákien. Každá skupina vlákien, s výnimkou systém
, musí mať nadradenú skupinu vlákien. Pre ThreadGroup (názov reťazca)
, rodič je skupina vlákien vlákna, ktoré volá ThreadGroup (názov reťazca)
. Ako príklad, ak volá hlavné vlákno ThreadGroup (názov reťazca)
, novovytvorená skupina vlákien má ako hlavnú skupinu hlavného vlákna–hlavný
. Pre ThreadGroup (ThreadGroup rodič, názov reťazca)
, rodič je skupina, ktorá rodič
referencie. Nasledujúci kód ukazuje, ako použiť tieto konštruktory na vytvorenie dvojice skupín vlákien:
public static void main (String [] args) {ThreadGroup tg1 = new ThreadGroup ("A"); ThreadGroup tg2 = nová ThreadGroup (tg1, "B"); }
V kóde vyššie vytvára hlavné vlákno dve skupiny vlákien: A
a B
. Najskôr sa vytvorí hlavné vlákno A
volaním ThreadGroup (názov reťazca)
. The tg1
-referencovaný rodič skupiny vlákien je hlavný
pretože hlavný
je skupina vlákien hlavného vlákna. Po druhé, vytvorí sa hlavné vlákno B
volaním ThreadGroup (ThreadGroup rodič, názov reťazca)
. The tg2
-referencovaný rodič skupiny vlákien je A
pretože tg1
odkaz je argumentom pre ThreadGroup (tg1, "B")
a A
asociuje s tg1
.
Tip: Akonáhle už nebudete potrebovať hierarchiu ThreadGroup
predmety, hovor ThreadGroup
je neplatné zničenie ()
metóda prostredníctvom odkazu na ThreadGroup
objekt na vrchole tejto hierarchie. Ak vrch ThreadGroup
objekt a všetky objekty podskupín neobsahujú objekty vlákien, zničiť ()
pripravuje tieto objekty skupín vlákien na zber odpadkov. Inak, zničiť ()
hodí IllegalThreadStateException
objekt. Kým však anulujete odkaz na začiatok ThreadGroup
objekt (za predpokladu, že premenná poľa obsahuje tento odkaz), smetiar nemôže tento objekt zhromaždiť. Podľa horného objektu môžete určiť, či bolo na telefónne číslo uskutočnené predchádzajúce volanie zničiť ()
metóda volaním ThreadGroup
je boolean isDestroyed ()
metóda. Táto metóda vráti hodnotu true, ak bola zničená hierarchia skupín vlákien.
Samotné skupiny vlákien sú zbytočné. Na akékoľvek použitie musia zoskupovať vlákna. Zoskupujete vlákna do skupín vlákien tak, že ich odovzdáte ThreadGroup
odkazy na príslušné Závit
konštruktéri:
ThreadGroup tg = new ThreadGroup ("podskupina 2"); Vlákno t = nové vlákno (tg, "moje vlákno");
Vyššie uvedený kód najskôr vytvorí a podskupina 2
skupina s hlavný
ako materská skupina. (Predpokladám, že hlavné vlákno vykoná kód.) Kód potom vytvorí a moje vlákno
Závit
objekt v podskupina 2
skupina.
Teraz vytvorme aplikáciu, ktorá vytvára hierarchickú štruktúru skupín vlákien našej postavy:
Zoznam 1. ThreadGroupDemo.java
// ThreadGroupDemo.java class ThreadGroupDemo {public static void main (String [] args) {ThreadGroup tg = new ThreadGroup ("subgroup 1"); Vlákno t1 = nové vlákno (tg, "vlákno 1"); Vlákno t2 = nové vlákno (tg, "vlákno 2"); Vlákno t3 = nové vlákno (tg, "vlákno 3"); tg = new ThreadGroup ("podskupina 2"); Vlákno t4 = nové vlákno (tg, "moje vlákno"); tg = Thread.currentThread () .getThreadGroup (); int agc = tg.activeGroupCount (); System.out.println ("Aktívne skupiny vlákien v skupine vlákien" + tg.getName () + ":" + agc); tg.list (); }}
ThreadGroupDemo
vytvorí príslušnú skupinu vlákien a objekty vlákien na zrkadlenie toho, čo vidíte na obrázku vyššie. Preukázať, že podskupina 1
a podskupina 2
skupiny sú hlavný
sú iba podskupiny, ThreadGroupDemo
robí toto:
- Načíta odkaz na hlavné vlákno
ThreadGroup
objekt zavolanímZávit
je statickýcurrentThread ()
metóda (ktorá vracia odkaz na hlavné vláknoZávit
objekt), za ktorým nasledujeZávit
jeThreadGroup getThreadGroup ()
metóda. - Vyzýva
ThreadGroup
jeint activeGroupCount ()
metóda na práve vrátenýThreadGroup
referencia na vrátenie odhadu aktívnych skupín v skupine vlákien hlavného vlákna. - Vyzýva
ThreadGroup
jeReťazec getName ()
metóda na vrátenie názvu skupiny vlákien hlavného vlákna. - Vyzýva
ThreadGroup
jezoznam neplatných ()
metóda tlače na štandardnom výstupnom zariadení podrobnosti o skupine vlákien hlavného vlákna a všetkých podskupinách.
Pri spustení, ThreadGroupDemo
zobrazí nasledujúci výstup:
Aktívne skupiny vlákien v hlavnej skupine vlákien: 2 java.lang.ThreadGroup [name = main, maxpri = 10] Thread [main, 5, main] Thread [Thread-0,5, main] java.lang.ThreadGroup [name = subgroup 1, maxpri = 10] vlákno [vlákno 1,5, podskupina 1] vlákno [vlákno 2,5, podskupina 1] vlákno [vlákno 3,5, podskupina 1] java.lang.ThreadGroup [name = podskupina 2, maxpri = 10 ] Vlákno [moje vlákno, 5, podskupina 2]
Výstup, ktorý sa začína na Závit
výsledky z zoznam ()
interné hovory do Závit
je natiahnuť()
metóda, výstupný formát, ktorý som popísal v časti 1. Spolu s týmto výstupom vidíte výstup začínajúci sa na java.lang.ThreadGroup
. Tento výstup identifikuje názov skupiny vlákien, za ktorým nasleduje jeho maximálna priorita.
Prioritné skupiny a skupiny vlákien
Maximálna priorita skupiny vlákien je najvyššia priorita, ktorú môže každé z jej vlákien dosiahnuť. Zvážte vyššie uvedený program sieťových serverov. V rámci tohto programu vlákno čaká na klientske programy a prijíma ich. Predtým, ako to urobíte, vlákno wait-for / accept-request najskôr vytvorí skupinu vlákien s maximálnou prioritou tesne pod prioritou tohto vlákna. Neskôr, keď príde žiadosť, vlákno čakania na / prijatie žiadosti vytvorí nové vlákno, ktoré bude reagovať na požiadavku klienta, a pridá nové vlákno do predtým vytvorenej skupiny vlákien. Priorita nového vlákna sa automaticky zníži na maximum skupiny vlákien. Týmto spôsobom vlákno Wait for / Accept-Request reaguje na žiadosti častejšie, pretože sa spúšťa častejšie.
Java pripisuje každej skupine vlákien maximálnu prioritu. Pri vytváraní skupiny získa Java túto prioritu od svojej nadradenej skupiny. Použite ThreadGroup
je void setMaxPriority (priorita int)
metóda na následné nastavenie maximálnej priority. Vlákna, ktoré do skupiny pridáte po nastavení maximálnej priority, nemôžu mať prioritu presahujúcu maximum. Akékoľvek vlákno s vyššou prioritou sa automaticky zníži, keď sa stane členom skupiny vlákien. Ak však použijete setMaxPriority (priorita int)
aby sa znížila maximálna priorita skupiny, všetky vlákna pridané do skupiny pred volaním tejto metódy si zachovajú svoje pôvodné priority. Napríklad ak pridáte vlákno priority 8 do skupiny s maximálnou prioritou 9 a potom znížite maximálnu prioritu tejto skupiny na 7, vlákno priority 8 zostane na priorite 8. Maximálnu prioritu skupiny vlákien môžete kedykoľvek určiť volaním ThreadGroup
je int getMaxPriority ()
metóda. Na demonštráciu skupín priorít a vlákien som napísal MaxPriorityDemo
:
Zoznam 2. MaxPriorityDemo.java
// MaxPriorityDemo.java trieda MaxPriorityDemo {public static void main (String [] args) {ThreadGroup tg = new ThreadGroup ("A"); System.out.println ("tg maximálna priorita =" + tg.getMaxPriority ()); Vlákno t1 = nové vlákno (tg, "X"); System.out.println ("priorita t1 =" + t1.getPriority ()); t1.setPriority (Thread.NORM_PRIORITY + 1); System.out.println ("priorita t1 po setPriority () =" + t1.getPriority ()); tg.setMaxPriority (Thread.NORM_PRIORITY - 1); System.out.println ("maximálna priorita tg po setMaxPriority () =" + tg.getMaxPriority ()); System.out.println ("priorita t1 po setMaxPriority () =" + t1.getPriority ()); Vlákno t2 = nové vlákno (tg, "Y"); System.out.println ("priorita t2 =" + t2.getPriority ()); t2.setPriority (Thread.NORM_PRIORITY); System.out.println ("priorita t2 po setPriority () =" + t2.getPriority ()); }}
Pri spustení, MaxPriorityDemo
vytvorí nasledujúci výstup:
tg maximálna priorita = 10 t1 priorita = 5 t1 priorita po setPriority () = 6 tg maximálna priorita po setMaxPriority () = 4 t1 priorita po setMaxPriority () = 6 t2 priorita = 4 t2 priorita po setPriority () = 4
Skupina vlákien A
(ktoré tg
referencie) sa začína najvyššou prioritou (10) ako jej maximom. Závit X
, ktorého Závit
objekt t1
referencie, pripojí sa ku skupine a dostane 5 ako svoju prioritu. Zmeníme prioritu tohto vlákna na 6, ktorá bude úspešná, pretože 6 je menej ako 10. Následne zavoláme setMaxPriority (priorita int)
znížiť maximálnu prioritu skupiny na 4. Aj keď vlákno X
zostáva na priorite 6, ktorá je novo pridaná Y.
vlákno dostane 4 ako svoju prioritu. Na záver pokus o zväčšenie vlákna Y.
priorita 5 zlyhá, pretože 5 je väčšia ako 4.
Poznámka:setMaxPriority (priorita int)
automaticky upravuje maximálnu prioritu podskupín skupiny vlákien.
Okrem použitia skupín vlákien na obmedzenie priority vlákien môžete vykonať ďalšie úlohy zavolaním rôznych ThreadGroup
metódy, ktoré sa vzťahujú na vlákno každej skupiny. Metódy zahŕňajú void suspend ()
, neplatný životopis ()
, void stop ()
a void interrupt ()
. Pretože spoločnosť Sun Microsystems zastarala prvé tri metódy (sú nebezpečné), preskúmame ich iba prerušiť()
.
Prerušte skupinu vlákien
ThreadGroup
je prerušiť()
metóda umožňuje vláknu prerušiť vlákna a podskupiny konkrétnej skupiny vlákien. Táto technika by sa ukázala ako vhodná v nasledujúcom scenári: Hlavné vlákno vašej aplikácie vytvára viac vlákien, z ktorých každé vykonáva jednotku práce. Pretože všetky vlákna musia dokončiť svoje príslušné pracovné jednotky, aby mohlo každé vlákno preskúmať výsledky, každé vlákno počká po dokončení svojej pracovnej jednotky. Hlavné vlákno sleduje pracovný stav. Len čo čakajú všetky ostatné vlákna, zavolá sa hlavné vlákno prerušiť()
prerušiť čakanie ostatných vlákien. Potom tieto vlákna môžu preskúmať a spracovať výsledky. Výpis 3 ukazuje prerušenie skupiny vlákien:
Zoznam 3. InterruptThreadGroup.java
// InterruptThreadGroup.java class InterruptThreadGroup {public static void main (String [] args) {MyThread mt = new MyThread (); mt.setName ("A"); mt.start (); mt = nový MyThread (); mt.setName ("B"); mt.start (); skus {Thread.sleep (2000); // Počkajte 2 sekundy} catch (InterruptedException e) {} // Prerušte všetky metódy v rovnakej skupine vlákien ako hlavné // vlákno Thread.currentThread () .getThreadGroup () .interrupt (); }} class MyThread extends Thread {public void run () {synchronized ("A") {System.out.println (getName () + "about to wait."); skúste {"A" .wait (); } catch (InterruptedException e) {System.out.println (getName () + "prerušené."); } System.out.println (getName () + "ukončenie."); }}}