Programmēšana

Java 101: Java pavedienu izpratne, 4. daļa: Vītņu grupas, svārstīgums un pavedienu lokālie mainīgie

Šī mēneša Java 101 noslēdz pavedienu sēriju, koncentrējoties uz pavedienu grupām, svārstīgumu, pavedienu lokālajiem mainīgajiem, taimeriem un ThreadDeath klasē.

Izpratne par Java pavedieniem - izlasiet visu sēriju

  • 1. daļa: Vītņu un skrējienu iepazīstināšana
  • 2. daļa: Vītnes sinhronizācija
  • 3. daļa: Vītņu plānošana, gaidīšana / paziņošana un pavedienu pārtraukšana
  • 4. daļa: pavedienu grupas, svārstīgums, lokālie pavedienu mainīgie, taimeri un pavedienu bojāeja

Vītņu grupas

Tīkla servera programmā viena pavediens gaida un pieņem klienta programmu pieprasījumus izpildīt, piemēram, datu bāzes darījumus vai sarežģītus aprēķinus. Vītne parasti izveido jaunu pavedienu, lai apstrādātu pieprasījumu. Atkarībā no pieprasījuma apjoma vienlaikus var būt daudz dažādu pavedienu, kas sarežģī pavedienu pārvaldību. Lai vienkāršotu pavedienu pārvaldību, programmas sakārto savus pavedienus pavedienu grupasjava.lang.ThreadGroup objekti, kas grupē saistītos pavedienus ' Vītne (un Vītne apakšklase) objekti. Piemēram, jūsu programma var izmantot ThreadGroup lai visus drukas pavedienus sagrupētu vienā grupā.

Piezīme: Lai diskusija būtu vienkārša, es atsaucos uz pavedienu grupām, it kā tās sakārtotu pavedienus. Patiesībā pavedienu grupas organizējas Vītne (un Vītne apakšklase) objekti, kas saistīti ar pavedieniem.

Java prasa katru pavedienu un katru pavedienu grupu - saglabājiet saknes pavedienu grupu, sistēmā- pievienoties kādai citai pavedienu grupai. Šī vienošanās noved pie hierarhiskas pavedienu grupas struktūras, kuru zemāk redzamais attēls ilustrē lietojuma kontekstā.

Attēla struktūras augšpusē ir sistēmā pavedienu grupa. JVM izveidots sistēmā grupa organizē JVM pavedienus, kas nodarbojas ar objektu pabeigšanu un citiem sistēmas uzdevumiem, un kalpo kā lietojumprogrammas hierarhiskās pavedienu grupas struktūras saknes pavedienu grupa. Tikai zemāk sistēmā ir JVM izveidots galvenais pavedienu grupa, kas ir sistēmāapakšvītņu grupa (īsāk - apakšgrupa). galvenais satur vismaz vienu pavedienu - JVM izveidoto galveno pavedienu, kas izpilda baita koda instrukcijas galvenais () metodi.

Zem galvenais grupa dzīvo 1. apakšgrupa un 2. apakšgrupa apakšgrupas, lietojumprogrammas izveidotas apakšgrupas (kuras attēla lietojumprogramma izveido). Turklāt 1. apakšgrupa sagrupē trīs lietojumprogrammas izveidotus pavedienus: 1. pavediens, 2. pavediens, un 3. pavediens. Turpretī 2. apakšgrupa sagrupē vienu lietojumprogrammas izveidotu pavedienu: mans pavediens.

Tagad, kad jūs zināt pamatus, sāksim veidot pavedienu grupas.

Izveidojiet pavedienu grupas un saistiet pavedienus ar šīm grupām

The ThreadGroup klases SDK dokumentācija atklāj divus konstruktorus: ThreadGroup (virknes nosaukums) un ThreadGroup (ThreadGroup vecāks, virknes nosaukums). Abi konstruktori izveido pavedienu grupu un piešķir tai nosaukumu nosaukums parametrs norāda. Konstruktori atšķiras pēc izvēles, kāda pavedienu grupa kalpo kā vecākā jaunizveidotajai pavedienu grupai. Katra pavedienu grupa, izņemot sistēmā, jābūt vecāku pavedienu grupai. Priekš ThreadGroup (virknes nosaukums), vecāks ir pavediena pavedienu grupa, kas izsauc ThreadGroup (virknes nosaukums). Piemēram, ja zvana galvenais pavediens ThreadGroup (virknes nosaukums), jaunizveidotajai pavedienu grupai ir galvenā pavediena grupa -galvenais. Priekš ThreadGroup (ThreadGroup vecāks, virknes nosaukums), vecāks ir tā grupa vecāks atsauces. Šis kods parāda, kā izmantot šos konstruktorus, lai izveidotu pavedienu grupu pāri:

public static void main (String [] args) {ThreadGroup tg1 = jauna ThreadGroup ("A"); ThreadGroup tg2 = jauna ThreadGroup (tg1, "B"); }

Iepriekš minētajā kodā galvenais pavediens izveido divas pavedienu grupas: A un B. Pirmkārt, galvenais pavediens rada A piezvanot ThreadGroup (virknes nosaukums). The tg1-referencē pavedienu grupas vecāks ir galvenais jo galvenais ir galvenā pavediena pavedienu grupa. Otrkārt, galvenais pavediens rada B piezvanot ThreadGroup (ThreadGroup vecāks, virknes nosaukums). The tg2-referencē pavedienu grupas vecāks ir A jo tg1atsauce pāriet kā arguments uz ThreadGroup (tg1, "B") un A asociējas ar tg1.

Padoms: Pēc tam, kad jums vairs nav nepieciešama hierarhija ThreadGroup objekti, zvaniet ThreadGroup's anulēt iznīcināt () metode, izmantojot atsauci uz ThreadGroup objekts šīs hierarhijas augšdaļā. Ja augšā ThreadGroup objektam un visiem apakšgrupas objektiem trūkst pavedienu objektu, iznīcināt() sagatavo tos pavedienu grupas objektus atkritumu savākšanai. Pretējā gadījumā iznīcināt() met an IllegalThreadStateException objekts. Tomēr, kamēr jūs neatceļat atsauci uz augšu ThreadGroup objektu (pieņemot, ka lauka mainīgajā ir šī atsauce), atkritumu savācējs nevar savākt šo objektu. Atsaucoties uz augšējo objektu, jūs varat noteikt, vai iepriekš tika zvanīts uz iznīcināt() metodi, zvanot ThreadGroup's Boolean isDestroyed () metodi. Šī metode atgriežas kā taisnība, ja pavedienu grupas hierarhija tika iznīcināta.

Pats par sevi pavedienu grupas ir bezjēdzīgas. Lai tos varētu izmantot, viņiem ir jāgrupē pavedieni. Jūs grupējat pavedienus pavedienu grupās, pārejot ThreadGroup atsauces uz piemērotu Vītne konstruktori:

ThreadGroup tg = jauna ThreadGroup ("2. apakšgrupa"); Thread t = new Thread (tg, "mans pavediens");

Iepriekš minētais kods vispirms izveido a 2. apakšgrupa grupa ar galvenais kā vecāku grupa. (Es pieņemu, ka galvenais pavediens izpilda kodu.) Nākamais kods izveido a mans pavediensVītne objekts 2. apakšgrupa grupa.

Tagad izveidosim lietojumprogrammu, kas izveido mūsu figūras hierarhisko pavedienu grupas struktūru:

Saraksts 1. ThreadGroupDemo.java

// ThreadGroupDemo.java klase ThreadGroupDemo {public static void main (String [] args) {ThreadGroup tg = jauna ThreadGroup ("1. apakšgrupa"); Pavediens t1 = jauns pavediens (tg, "pavediens 1"); Pavediens t2 = jauns pavediens (tg, "pavediens 2"); Pavediens t3 = jauns pavediens (tg, "pavediens 3"); tg = jauna ThreadGroup ("2. apakšgrupa"); Pavediens t4 = jauns pavediens (tg, "mans pavediens"); tg = Thread.currentThread () .getThreadGroup (); int agc = tg.activeGroupCount (); System.out.println ("Aktīvās pavedienu grupas" + tg.getName () + "pavedienu grupā:" + agc); tg.list (); }}

ThreadGroupDemo izveido atbilstošu pavedienu grupu un pavedienu objektus, lai atspoguļotu to, ko redzat attēlā. Lai pierādītu, ka 1. apakšgrupa un 2. apakšgrupa grupas ir galvenaisir tikai apakšgrupas, ThreadGroupDemo veic šādas darbības:

  1. Izgūst atsauci uz galvenajiem pavedieniem ThreadGroup iebilst, piezvanot Vītneir statiska currentThread () metode (kas atgriež atsauci uz galvenajiem pavedieniem Vītne objekts), kam seko Vītne's ThreadGroup getThreadGroup () metodi.
  2. Zvani ThreadGroup's int activeGroupCount () metode tikko atgrieztajā ThreadGroup atsauce, lai atgrieztu aktīvo grupu tāmi galvenā pavediena pavedienu grupā.
  3. Zvani ThreadGroup's Virkne getName () metode, lai atgrieztu galvenā pavediena pavedienu grupas nosaukumu.
  4. Zvani ThreadGroup's nederīgs saraksts () metode, kā drukāt uz standarta izvades ierīces informāciju par galvenā pavediena pavedienu grupu un visām apakšgrupām.

Palaist, ThreadGroupDemo parāda šādu izvadi:

Aktīvās pavedienu grupas galvenajā pavedienu grupā: 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] Vītne [pavediens 1,5, 1. apakšgrupa] Vītne [pavediens 2,5, 1. apakšgrupa] Vītne [pavediens 3,5, 1. apakšgrupa] java.lang.ThreadGroup [nosaukums = 2. apakšgrupa, maxpri = 10 ] Vītne [mans pavediens, 5., 2. apakšgrupa]

Rezultāts, kas sākas ar Vītne rezultāti no saraksts ()iekšējie zvani uz Vītne's toString () metodi, izejas formātu, kuru es aprakstīju 1. daļā. Kopā ar šo izvadi jūs redzat izvades sākumu ar java.lang.ThreadGroup. Šī izeja identificē pavedienu grupas nosaukumu, kam seko tā maksimālā prioritāte.

Prioritātes un pavedienu grupas

Pavedienu grupas maksimālā prioritāte ir augstākā prioritāte, kādu var sasniegt visi tās pavedieni. Apsveriet iepriekš minēto tīkla servera programmu. Šīs programmas ietvaros pavediens gaida un pieņem klienta programmu pieprasījumus. Pirms to izdarīt, gaidīšanas / pieņemšanas pieprasījuma pavediens vispirms var izveidot pavedienu grupu ar maksimālo prioritāti tieši zem šīs pavediena prioritātes. Vēlāk, kad pienāk pieprasījums, gaidīšanas / pieņemšanas-pieprasījuma pavediens izveido jaunu pavedienu, lai atbildētu uz klienta pieprasījumu, un pievieno jaunu pavedienu iepriekš izveidotajai pavedienu grupai. Jaunā pavediena prioritāte automātiski samazinās līdz maksimālajai pavedienu grupai. Tādā veidā gaidīšanas / pieņemšanas-pieprasījuma pavediens biežāk reaģē uz pieprasījumiem, jo ​​tas darbojas biežāk.

Java katrai pavedienu grupai piešķir maksimālo prioritāti. Kad izveidojat grupu, Java iegūst šo prioritāti no vecāku grupas. Izmantot ThreadGroup's void setMaxPriority (int prioritāte) metodi pēc tam noteikt maksimālo prioritāti. Visiem pavedieniem, kurus pievienojat grupai pēc maksimālās prioritātes iestatīšanas, prioritāte nedrīkst pārsniegt maksimālo. Jebkurš pavediens ar augstāku prioritāti automātiski pazeminās, pievienojoties pavedienu grupai. Tomēr, ja jūs izmantojat setMaxPriority (int prioritāte) lai pazeminātu grupas maksimālo prioritāti, visi grupai pirms šīs metodes izsaukuma pievienotie pavedieni saglabā to sākotnējās prioritātes. Piemēram, ja jūs pievienojat 8. prioritātes pavedienu maksimālās 9. grupas grupai un pēc tam pazemina šīs grupas maksimālo prioritāti līdz 7, 8. prioritātes pavediens paliek prioritārā 8. Jebkurā laikā varat noteikt pavedienu grupas maksimālo prioritāti, zvanot ThreadGroup's int getMaxPriority () metodi. Lai parādītu prioritāšu un pavedienu grupas, es uzrakstīju MaxPriorityDemo:

Saraksts 2. MaxPriorityDemo.java

// MaxPriorityDemo.java klase MaxPriorityDemo {public static void main (String [] args) {ThreadGroup tg = new ThreadGroup ("A"); System.out.println ("tg maksimālā prioritāte =" + tg.getMaxPriority ()); Pavediens t1 = jauns pavediens (tg, "X"); System.out.println ("t1 prioritāte =" + t1.getPriority ()); t1.setPriority (Thread.NORM_PRIORITY + 1); System.out.println ("t1 prioritāte pēc setPriority () =" + t1.getPriority ()); tg.setMaxPriority (Thread.NORM_PRIORITY - 1); System.out.println ("tg maksimālā prioritāte pēc setMaxPriority () =" + tg.getMaxPriority ()); System.out.println ("t1 prioritāte pēc setMaxPriority () =" + t1.getPriority ()); Pavediens t2 = jauns pavediens (tg, "Y"); System.out.println ("t2 prioritāte =" + t2.getPriority ()); t2.setPriority (Thread.NORM_PRIORITY); System.out.println ("t2 prioritāte pēc setPriority () =" + t2.getPriority ()); }}

Palaist, MaxPriorityDemo rada šādu izvadi:

tg maksimālā prioritāte = 10 t1 prioritāte = 5 t1 prioritāte pēc setPriority () = 6 tg maksimālā prioritāte pēc setMaxPriority () = 4 t1 prioritāte pēc setMaxPriority () = 6 t2 prioritāte = 4 t2 prioritāte pēc setPriority () = 4

Vītņu grupa A (kas tg atsauces) sākas ar augstāko prioritāti (10) kā maksimumu. Vītne X, kura Vītne objekts t1 atsauces, pievienojas grupai un par prioritāti saņem 5. Mēs mainām šī pavediena prioritāti uz 6, kas izdodas, jo 6 ir mazāks par 10. Pēc tam mēs piezvanām setMaxPriority (int prioritāte) lai samazinātu grupas maksimālo prioritāti līdz 4. Lai arī pavediens X joprojām ir 6. pievienotā prioritāte pavediens par prioritāti saņem 4. Visbeidzot, mēģinājums palielināt pavedienu Prioritāte līdz 5 neizdodas, jo 5 ir lielāka par 4.

Piezīme:setMaxPriority (int prioritāte) automātiski pielāgo pavedienu grupas apakšgrupu maksimālo prioritāti.

Papildus pavedienu grupu izmantošanai, lai ierobežotu pavedienu prioritāti, varat veikt arī citus uzdevumus, izsaucot dažādus ThreadGroup metodes, kas attiecas uz katras grupas pavedieniem. Metodes ietver anulēt apturēšanu (), anulēt atsākt (), anulēt pieturu (), un anulēt pārtraukumu (). Tā kā Sun Microsystems ir novecojusi pirmās trīs metodes (tās ir nedrošas), mēs tikai pārbaudām pārtraukt ().

Pārtrauciet pavedienu grupu

ThreadGroup's pārtraukt () metode ļauj pavedienam pārtraukt noteiktas pavedienu grupas pavedienus un apakšgrupas. Šis paņēmiens izrādīsies piemērots šādā gadījumā: Jūsu lietojumprogrammas galvenais pavediens izveido vairākus pavedienus, no kuriem katrs veic darba vienību. Tā kā visiem pavedieniem ir jāpabeidz attiecīgās darba vienības, pirms kāds pavediens var pārbaudīt rezultātus, katrs pavediens gaida pēc darba vienības pabeigšanas. Galvenais pavediens uzrauga darba stāvokli. Kad visi citi pavedieni ir gaidījuši, galvenais pavediens izsauc pārtraukt () pārtraukt citu pavedienu gaidīšanu. Tad šie pavedieni var pārbaudīt un apstrādāt rezultātus. 3. saraksts parāda pavedienu grupas pārtraukumu:

Saraksts 3. InterruptThreadGroup.java

// InterruptThreadGroup.java klase InterruptThreadGroup {public static void main (String [] args) {MyThread mt = new MyThread (); mt.setName ("A"); mt.start (); mt = new MyThread (); mt.setName ("B"); mt.start (); izmēģiniet {Thread.sleep (2000); // Pagaidiet 2 sekundes} catch (InterruptedException e) {} // Pārtrauciet visas metodes vienā pavedienu grupā ar galveno // pavedienu Thread.currentThread () .getThreadGroup () .interrupt (); }} klase MyThread paplašina Thread {public void run () {synchronized ("A") {System.out.println (getName () + "gatavojas gaidīt."); mēģiniet {"A" .gaidiet (); } catch (InterruptedException e) {System.out.println (getName () + "pārtraukts"); } System.out.println (getName () + "beidzas"); }}}
$config[zx-auto] not found$config[zx-overlay] not found