Programmering

Java 101: Forstå Java-tråder, del 4: Trådgrupper, volatilitet og tråd-lokale variabler

Denne månedens Java 101 avslutter trådserien med å fokusere på trådgrupper, volatilitet, tråd-lokale variabler, tidtakere og TrådDød klasse.

Forstå Java-tråder - les hele serien

  • Del 1: Introduksjon av tråder og løpere
  • Del 2: Trådesynkronisering
  • Del 3: Trådplanlegging, vent / varsling og trådavbrudd
  • Del 4: Trådgrupper, volatilitet, tråd-lokale variabler, tidtakere og tråddød

Trådgrupper

I et nettverksserverprogram venter en tråd på og godtar forespørsler fra klientprogrammer om å utføre, for eksempel databasetransaksjoner eller komplekse beregninger. Tråden oppretter vanligvis en ny tråd for å håndtere forespørselen. Avhengig av forespørselsvolumet, kan mange forskjellige tråder være til stede samtidig, noe som kompliserer trådadministrasjonen. For å forenkle trådadministrasjon, organiserer programmer trådene sine med trådgrupperjava.lang.ThreadGroup objekter som grupperer relaterte tråder ' Tråd (og Tråd underklasse) objekter. For eksempel kan programmet ditt bruke Trådgruppe for å gruppere alle utskriftstrådene i en gruppe.

Merk: For å holde diskusjonen enkel refererer jeg til trådgrupper som om de organiserer tråder. I virkeligheten organiserer trådgrupper Tråd (og Tråd underklasse) objekter tilknyttet tråder.

Java krever hver tråd og hver trådgruppe - lagre rottrådgruppen, system—For å bli med i en annen trådgruppe. Denne ordningen fører til en hierarkisk trådgruppestruktur, som figuren nedenfor illustrerer i en applikasjonssammenheng.

På toppen av figurens struktur er system trådgruppe. JVM-opprettet system group organiserer JVM-tråder som håndterer objektavslutning og andre systemoppgaver, og fungerer som rottrådgruppe i applikasjonens hierarkiske trådgruppestruktur. Rett under system er det JVM-laget hoved- trådgruppe, som er systemsin undertrådegruppe (undergruppe, for kort). hoved- inneholder minst én tråd - den JVM-opprettet hovedtråden som utfører byte-kodeinstruksjoner i hoved() metode.

Under hoved- gruppen bor i undergruppe 1 og undergruppe 2 undergrupper, applikasjonsopprettede undergrupper (som figurens applikasjon oppretter). Dessuten, undergruppe 1 grupperer tre applikasjonsopprettede tråder: tråd 1, tråd 2, og tråd 3. I motsetning, undergruppe 2 grupperer en applikasjonsopprettet tråd: tråden min.

Nå som du vet det grunnleggende, la oss begynne å lage trådgrupper.

Opprett trådgrupper og knytt tråder til disse gruppene

De Trådgruppe klassens SDK-dokumentasjon avslører to konstruktører: ThreadGroup (strengnavn) og ThreadGroup (overordnet ThreadGroup, strengnavn). Begge konstruktørene oppretter en trådgruppe og gir den et navn, som Navn parameter spesifiserer. Konstruktørene skiller seg i valg av hvilken trådgruppe som fungerer som overordnet til den nyopprettede trådgruppen. Hver trådgruppe, unntatt system, må ha en overordnet trådgruppe. Til ThreadGroup (strengnavn), er overordnet trådgruppen til tråden som ringer ThreadGroup (strengnavn). Som et eksempel, hvis hovedtråden ringer ThreadGroup (strengnavn), den nyopprettede trådgruppen har hovedtrådens gruppe som overordnet—hoved-. Til ThreadGroup (overordnet ThreadGroup, strengnavn), foreldrene er gruppen som foreldre referanser. Følgende kode viser hvordan du bruker disse konstruktørene til å lage et par trådgrupper:

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

I koden ovenfor oppretter hovedtråden to trådgrupper: EN og B. For det første skaper hovedtråden EN ved å ringe ThreadGroup (strengnavn). De tg1- referert trådgruppens foreldre er hoved- fordi hoved- er hovedtrådens trådgruppe. For det andre skaper hovedtråden B ved å ringe ThreadGroup (overordnet ThreadGroup, navn på streng). De tg2- referert trådgruppens foreldre er EN fordi tg1referanse går som et argument til Trådgruppe (tg1, "B") og EN forbinder med tg1.

Tips: Når du ikke lenger trenger et hierarki av Trådgruppe gjenstander, ring Trådgruppes ugyldig ødelegge () metoden via en referanse til Trådgruppe objekt på toppen av det hierarkiet. Hvis toppen Trådgruppe objekt og alle undergruppeobjekter mangler trådobjekter, ødelegge() forbereder trådgruppegjenstandene for søppeloppsamling. Ellers, ødelegge() kaster en IllegalThreadStateException gjenstand. Imidlertid til du opphever referansen til toppen Trådgruppe objekt (forutsatt at en feltvariabel inneholder den referansen), kan ikke søppeloppsamleren samle inn det objektet. Med henvisning til det øverste objektet kan du avgjøre om en tidligere samtale ble ringt til ødelegge() metode ved å ringe Trådgruppes boolsk er ødelagt () metode. Denne metoden blir sant hvis trådgruppehierarkiet ble ødelagt.

I seg selv er trådgrupper ubrukelige. For å være til nytte må de gruppere tråder. Du grupperer tråder i trådgrupper ved å passere Trådgruppe referanser til passende Tråd konstruksjoner:

ThreadGroup tg = new ThreadGroup ("undergruppe 2"); Tråd t = ny tråd (tg, "tråden min");

Koden ovenfor oppretter først en undergruppe 2 gruppe med hoved- som foreldregruppe. (Jeg antar at hovedtråden utfører koden.) Koden oppretter deretter en tråden minTråd objekt i undergruppe 2 gruppe.

La oss nå lage et program som produserer figurens hierarkiske trådgruppestruktur:

Oppføring 1. ThreadGroupDemo.java

// ThreadGroupDemo.java klasse ThreadGroupDemo {public static void main (String [] args) {ThreadGroup tg = new ThreadGroup ("subgroup 1"); Tråd t1 = ny tråd (tg, "tråd 1"); Tråd t2 = ny tråd (tg, "tråd 2"); Tråd t3 = ny tråd (tg, "tråd 3"); tg = ny trådgruppe ("undergruppe 2"); Tråd t4 = ny tråd (tg, "tråden min"); tg = Thread.currentThread () .getThreadGroup (); int agc = tg.activeGroupCount (); System.out.println ("Aktive trådgrupper i" + tg.getName () + "trådgruppe:" + agc); tg.list (); }}

ThreadGroupDemo oppretter riktig trådgruppe og trådobjekter for å speile det du ser i figuren ovenfor. For å bevise at undergruppe 1 og undergruppe 2 grupper er hoved-bare undergrupper, ThreadGroupDemo gjør følgende:

  1. Henter en referanse til hovedtråden Trådgruppe objekt ved å ringe Tråder statisk gjeldende tråd () metode (som returnerer en referanse til hovedtråden Tråd objekt) etterfulgt av Tråds ThreadGroup getThreadGroup () metode.
  2. Ringer Trådgruppes int activeGroupCount () metoden på nettopp returnerte Trådgruppe referanse for å returnere et estimat av aktive grupper innenfor hovedtrådens trådgruppe.
  3. Ringer Trådgruppes String getName () metode for å returnere hovedtrådens trådgruppenavn.
  4. Ringer Trådgruppes ugyldig liste () metode for å skrive ut på standard utdataenhetsdetaljer på hovedtrådens trådgruppe og alle undergrupper.

Når du løper, ThreadGroupDemo viser følgende utgang:

Aktive trådgrupper i hovedtrådgruppe: 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] Tråd [tråd 1,5, undergruppe 1] Tråd [tråd 2,5, undergruppe 1] Tråd [tråd 3,5, undergruppe 1] java.lang.ThreadGroup [navn = undergruppe 2, maxpri = 10 ] Tråd [tråden min, 5, undergruppe 2]

Utgang som begynner med Tråd resultater fra liste()sine interne samtaler til Tråds toString () metode, et utdataformat jeg beskrev i del 1. Sammen med den utgangen ser du utdata som begynner med java.lang.ThreadGroup. Denne utgangen identifiserer trådgruppens navn etterfulgt av maksimal prioritet.

Prioritets- og trådgrupper

En trådgruppes maksimale prioritet er den høyeste prioriteten noen av trådene kan oppnå. Tenk på det nevnte nettverksserverprogrammet. Innenfor programmet venter en tråd på og godtar forespørsler fra klientprogrammer. Før du gjør det, kan ventetiden / godta-forespørselstråden først opprette en trådgruppe med maksimal prioritet rett under trådens prioritet. Senere, når en forespørsel kommer, oppretter ventetiden / godtar forespørselstråden en ny tråd for å svare på klientforespørselen og legger til den nye tråden i den tidligere opprettede trådgruppen. Den nye trådens prioritet senkes automatisk til trådgruppens maksimum. På den måten svarer ventetiden / godta-forespørselstråden oftere på forespørsler fordi den kjører oftere.

Java tildeler maksimal prioritet til hver trådgruppe. Når du oppretter en gruppe, får Java den prioriteten fra foreldregruppen. Bruk Trådgruppes ugyldig setMaxPriority (int prioritet) metode for å deretter sette maksimal prioritet. Alle tråder du legger til i gruppen etter at du har angitt maksimal prioritet, kan ikke ha en prioritet som overstiger maksimumet. Enhver tråd med høyere prioritet senkes automatisk når den blir med i trådgruppen. Imidlertid, hvis du bruker setMaxPriority (int prioritet) for å senke en gruppes maksimale prioritet, beholder alle trådene som legges til gruppen før metoden, de opprinnelige prioriteringene. Hvis du for eksempel legger til en prioritet 8-tråd til en gruppe med maksimal prioritet 9, og deretter senker gruppens maksimale prioritet til 7, forblir prioritet 8-tråden i prioritet 8. Du kan når som helst bestemme en trådgruppes maksimale prioritet Trådgruppes int getMaxPriority () metode. For å demonstrere prioritets- og trådgrupper, skrev jeg MaxPriorityDemo:

Oppføring 2. MaxPriorityDemo.java

// MaxPriorityDemo.java klasse MaxPriorityDemo {public static void main (String [] args) {ThreadGroup tg = new ThreadGroup ("A"); System.out.println ("tg maksimal prioritet =" + tg.getMaxPriority ()); Tråd t1 = ny tråd (tg, "X"); System.out.println ("t1 prioritet =" + t1.getPriority ()); t1.setPriority (Thread.NORM_PRIORITY + 1); System.out.println ("t1 prioritet etter setPriority () =" + t1.getPriority ()); tg.setMaxPriority (tråd.NORM_PRIORITY - 1); System.out.println ("tg maksimal prioritet etter setMaxPriority () =" + tg.getMaxPriority ()); System.out.println ("t1 prioritet etter setMaxPriority () =" + t1.getPriority ()); Tråd t2 = ny tråd (tg, "Y"); System.out.println ("t2 prioritet =" + t2.getPriority ()); t2.setPriority (tråd.NORM_PRIORITY); System.out.println ("t2 prioritet etter setPriority () =" + t2.getPriority ()); }}

Når du løper, MaxPriorityDemo produserer følgende utgang:

tg maksimal prioritet = 10 t1 prioritet = 5 t1 prioritet etter sett Prioritet () = 6 tg maksimal prioritet etter settMaksPrioritet () = 4 t1 prioritet etter sett

Trådgruppe EN (hvilken tg referanser) starter med høyeste prioritet (10) som maksimum. Tråd X, hvem sin Tråd gjenstand t1 referanser, blir med i gruppen og får 5 som prioritet. Vi endrer trådens prioritet til 6, som lykkes fordi 6 er mindre enn 10. Deretter kaller vi setMaxPriority (int prioritet) for å redusere gruppens maksimale prioritet til 4. Selv om tråden X forblir på prioritet 6, en nylig lagt til Y tråden mottar 4 som sin prioritet. Endelig et forsøk på å øke tråden Yprioritet til 5 mislykkes, fordi 5 er større enn 4.

Merk:setMaxPriority (int prioritet) justerer automatisk maksimal prioritet for en trådgruppes undergrupper.

I tillegg til å bruke trådgrupper for å begrense trådprioritet, kan du utføre andre oppgaver ved å ringe forskjellige Trådgruppe metoder som gjelder for hver gruppes tråd. Metoder inkluderer ugyldig suspendere (), ugyldig CV (), ugyldig stopp (), og ugyldig avbrudd (). Fordi Sun Microsystems har avviklet de tre første metodene (de er usikre), undersøker vi bare avbryte().

Avbryt en trådgruppe

Trådgruppes avbryte() metoden lar en tråd avbryte trådene og undergruppene til en bestemt trådgruppe. Denne teknikken vil vise seg å være hensiktsmessig i følgende scenario: Programmets hovedtråd oppretter flere tråder som hver utfører en arbeidsenhet. Fordi alle tråder må fullføre sine respektive arbeidsenheter før en tråd kan undersøke resultatene, venter hver tråd etter å ha fullført arbeidsenheten. Hovedtråden overvåker arbeidstilstanden. Når alle andre tråder venter, ringer hovedtråden avbryte() å avbryte ventetiden til de andre trådene. Så kan disse trådene undersøke og behandle resultatene. Oppføring 3 demonstrerer avbrudd i trådgruppen:

Oppføring 3. InterruptThreadGroup.java

// InterruptThreadGroup.java klasse InterruptThreadGroup {public static void main (String [] args) {MyThread mt = new MyThread (); mt.setName ("A"); mt.start (); mt = ny MyThread (); mt.setName ("B"); mt.start (); prøv {Thread.sleep (2000); // Vent 2 sekunder} fangst (InterruptedException e) {} // Avbryt alle metodene i samme trådgruppe som hoved // thread Thread.currentThread () .getThreadGroup () .interrupt (); }} klasse MyThread utvider tråd {public void run () {synkronisert ("A") {System.out.println (getName () + "i ferd med å vente."); prøv {"A" .wait (); } fange (InterruptedException e) {System.out.println (getName () + "avbrutt."); } System.out.println (getName () + "avslutter."); }}}
$config[zx-auto] not found$config[zx-overlay] not found