Programmering

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

Denne måned er Java 101 afslutter trådserien ved at fokusere på trådgrupper, volatilitet, tråd-lokale variabler, timere og TrådDød klasse.

Forståelse af Java-tråde - læs hele serien

  • Del 1: Introduktion af tråde og løbere
  • Del 2: Trådsynkronisering
  • Del 3: Trådplanlægning, vent / underret og trådafbrydelse
  • Del 4: Trådgrupper, volatilitet, tråd-lokale variabler, timere og tråddød

Trådgrupper

I et netværksserverprogram venter en tråd på og accepterer anmodninger fra klientprogrammer om at udføre for eksempel databasetransaktioner eller komplekse beregninger. Tråden opretter normalt en ny tråd til at håndtere anmodningen. Afhængig af anmodningsvolumen kan mange forskellige tråde være til stede samtidigt, hvilket komplicerer trådadministration. For at forenkle trådadministration organiserer programmer deres tråde med trådgrupperjava.lang.ThreadGroup objekter, der grupperer relaterede tråde ' Tråd (og Tråd underklasse) objekter. For eksempel kan dit program bruge Trådgruppe at gruppere alle udskrivningstråde i en gruppe.

Bemærk: For at holde diskussionen enkel henviser jeg til trådgrupper, som om de organiserer tråde. I virkeligheden organiserer trådgrupper Tråd (og Tråd underklasse) objekter tilknyttet tråde.

Java kræver hver tråd og hver trådgruppe - gem rodtrådgruppen, system—For at deltage i en anden trådgruppe. Dette arrangement fører til en hierarkisk trådgruppestruktur, som figuren nedenfor illustrerer i en applikationskontekst.

Øverst i figurens struktur er system trådgruppe. Den JVM-oprettede system gruppe organiserer JVM-tråde, der beskæftiger sig med objektafslutning og andre systemopgaver, og fungerer som rodtrådgruppen i en applikations hierarkiske trådgruppestruktur. Lige nedenunder system er det JVM-oprettede vigtigste trådgruppe, hvilket er system's undertrådsgruppe (undergruppe, for kort). vigtigste indeholder mindst én tråd - den JVM-oprettede hovedtråd, der udfører byte-kodeinstruktioner i hoved () metode.

Under vigtigste gruppe bor i undergruppe 1 og undergruppe 2 undergrupper, applikationsoprettede undergrupper (som figurens applikation opretter). Desuden, undergruppe 1 grupperer tre applikationsoprettede tråde: tråd 1, tråd 2og tråd 3. I modsætning, undergruppe 2 grupperer en applikationsoprettet tråd: min tråd.

Nu hvor du kender det grundlæggende, lad os begynde at oprette trådgrupper.

Opret trådgrupper og knyt tråde til disse grupper

Det Trådgruppe klassens SDK-dokumentation afslører to konstruktører: Trådgruppe (strengnavn) og ThreadGroup (forælder til ThreadGroup, strengnavn). Begge konstruktører opretter en trådgruppe og giver den et navn som navn parameter specificerer. Konstruktørerne adskiller sig i deres valg af hvilken trådgruppe der fungerer som overordnet til den nyoprettede trådgruppe. Hver trådgruppe undtagen system, skal have en overordnet trådgruppe. Til Trådgruppe (strengnavn), er den overordnede trådgruppen for den tråd, der kalder Trådgruppe (strengnavn). Som et eksempel, hvis hovedtråden kalder Trådgruppe (strengnavn), den nyoprettede trådgruppe har hovedtrådens gruppe som overordnet—vigtigste. Til ThreadGroup (forælder til ThreadGroup, strengnavn), forælderen er den gruppe, der forælder referencer. Følgende kode viser, hvordan man bruger disse konstruktører til at oprette et par trådgrupper:

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

I koden ovenfor opretter hovedtråden to trådgrupper: EN og B. For det første opretter hovedtråden EN ved at ringe Trådgruppe (strengnavn). Det tg1-omtalte trådgruppes forælder er vigtigste fordi vigtigste er hovedtrådens trådgruppe. For det andet opretter hovedtråden B ved at ringe ThreadGroup (forælder til ThreadGroup, strengnavn). Det tg2-omtalte trådgruppes forælder er EN fordi tg1's reference går som et argument til Trådgruppe (tg1, "B") og EN forbinder med tg1.

Tip: Når du ikke længere har brug for et hierarki af Trådgruppe genstande, ring Trådgruppe's ugyldig ødelægge () metode via en henvisning til Trådgruppe objekt øverst i dette hierarki. Hvis toppen Trådgruppe objekt og alle undergruppeobjekter mangler trådobjekter, ødelægge() forbereder disse trådgruppegenstande til affaldsindsamling. Ellers, ødelægge() kaster en IllegalThreadStateException objekt. Imidlertid indtil du annullerer henvisningen til toppen Trådgruppe objekt (forudsat at en feltvariabel indeholder denne reference), kan affaldssamleren ikke samle det objekt. Med henvisning til det øverste objekt kan du afgøre, om et tidligere opkald blev foretaget til ødelægge() metode ved at ringe Trådgruppe's boolsk er ødelagt () metode. Denne metode returnerer sandt, hvis trådgruppehierarkiet blev ødelagt.

Trådgrupper er i sig selv ubrugelige. For at være til nytte skal de gruppere tråde. Du grupperer tråde i trådgrupper ved at passere Trådgruppe henvisninger til passende Tråd konstruktører:

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

Koden ovenfor opretter først en undergruppe 2 gruppe med vigtigste som forældregruppe. (Jeg antager, at hovedtråden udfører koden.) Koden opretter derefter en min trådTråd objekt i undergruppe 2 gruppe.

Lad os nu oprette en applikation, der producerer vores figurens hierarkiske trådgruppestruktur:

Fortegnelse 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, "min tråd"); tg = Thread.currentThread () .getThreadGroup (); int agc = tg.activeGroupCount (); System.out.println ("Aktive trådgrupper i" + tg.getName () + "trådgruppe:" + agc); tg.list (); }}

ThreadGroupDemo opretter den passende trådgruppe og trådobjekter for at spejle det, du ser i figuren ovenfor. For at bevise, at undergruppe 1 og undergruppe 2 grupper er vigtigsteer kun undergrupper, ThreadGroupDemo gør følgende:

  1. Henter en henvisning til hovedtråden Trådgruppe objekt ved at ringe Tråder statisk nuværende tråd () metode (som returnerer en henvisning til hovedtråden Tråd objekt) efterfulgt af Tråd's ThreadGroup getThreadGroup () metode.
  2. Opkald Trådgruppe's int activeGroupCount () metode på netop returneret Trådgruppe reference for at returnere et skøn over aktive grupper inden for hovedtrådens trådgruppe.
  3. Opkald Trådgruppe's String getName () metode til at returnere hovedtrådens trådgruppenavn.
  4. Opkald Trådgruppe's ugyldig liste () metode til at udskrive på standardoutputenhedsoplysninger om hovedtrådens trådgruppe og alle undergrupper.

Når du kører, ThreadGroupDemo viser følgende output:

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 [min tråd, 5, undergruppe 2]

Output, der begynder med Tråd resultater fra liste()'s interne opkald til Tråd's toString () metode, et outputformat, jeg beskrev i del 1. Sammen med dette output ser du output, der begynder med java.lang.ThreadGroup. Denne output identificerer trådgruppens navn efterfulgt af dets maksimale prioritet.

Prioritets- og trådgrupper

En trådgruppes maksimale prioritet er den højeste prioritet, som nogen af ​​dens tråde kan nå. Overvej ovennævnte netværksserverprogram. Inden for dette program venter en tråd på og accepterer anmodninger fra klientprogrammer. Inden du gør det, kan vent-til-accept-anmodningstråden muligvis først oprette en trådgruppe med en maksimal prioritet lige under trådens prioritet. Senere, når en anmodning ankommer, opretter ventetiden / accepter-anmodningstråden en ny tråd til at svare på klientanmodningen og tilføjer den nye tråd til den tidligere oprettede trådgruppe. Den nye tråds prioritet sænkes automatisk til trådgruppens maksimum. På den måde reagerer ventetiden / accepter-anmodningstråden oftere på anmodninger, fordi den kører oftere.

Java tildeler en maksimal prioritet til hver trådgruppe. Når du opretter en gruppe, opnår Java denne prioritet fra sin overordnede gruppe. Brug Trådgruppe's ugyldigt setMaxPriority (int-prioritet) metode til efterfølgende at indstille den maksimale prioritet. Alle tråde, som du føjer til gruppen efter indstilling af dens maksimale prioritet, kan ikke have en prioritet, der overstiger maksimumet. Enhver tråd med en højere prioritet sænkes automatisk, når den slutter sig til trådgruppen. Men hvis du bruger setMaxPriority (int-prioritet) for at sænke en gruppes maksimale prioritet, beholder alle tråde, der føjes til gruppen før metoden, deres oprindelige prioriteter. For eksempel, hvis du tilføjer en prioritet 8 tråd til en gruppe med maksimal prioritet 9 og derefter sænker gruppens maksimale prioritet til 7, forbliver prioritet 8 tråd ved prioritet 8. Du kan til enhver tid bestemme en trådgruppes maksimale prioritet ved at ringe Trådgruppe's int getMaxPriority () metode. For at demonstrere prioritets- og trådgrupper skrev jeg MaxPriorityDemo:

Notering 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 efter setPriority () =" + t1.getPriority ()); tg.setMaxPriority (tråd.NORM_PRIORITY - 1); System.out.println ("tg maksimal prioritet efter setMaxPriority () =" + tg.getMaxPriority ()); System.out.println ("t1 prioritet efter 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 efter setPriority () =" + t2.getPriority ()); }}

Når du kører, MaxPriorityDemo producerer følgende output:

tg maksimal prioritet = 10 t1 prioritet = 5 t1 prioritet efter indstillet Prioritet () = 6 tg maksimal prioritet efter indstillet Max Prioritet () = 4 t 1 prioritet efter indstillet Max Prioritet () = 6 t2 prioritet = 4 t2 prioritet efter indstillet Prioritet () = 4

Trådgruppe EN (hvilken tg referencer) starter med den højeste prioritet (10) som maksimum. Tråd x, hvis Tråd objekt t1 referencer, slutter sig til gruppen og får 5 som sin prioritet. Vi ændrer trådens prioritet til 6, hvilket lykkes, fordi 6 er mindre end 10. Derefter kalder vi setMaxPriority (int-prioritet) for at reducere gruppens maksimale prioritet til 4. Selvom tråd x forbliver på prioritet 6, en ny tilføjet Y tråd modtager 4 som sin prioritet. Endelig et forsøg på at øge tråden Yprioritet til 5 mislykkes, fordi 5 er større end 4.

Bemærk:setMaxPriority (int-prioritet) justerer automatisk den maksimale prioritet for en trådgruppes undergrupper.

Ud over at bruge trådgrupper til at begrænse trådprioritet, kan du udføre andre opgaver ved at ringe til forskellige Trådgruppe metoder, der gælder for hver gruppes tråd. Metoder inkluderer ugyldig suspendere (), ugyldigt CV (), ugyldigt stop ()og ugyldig afbrydelse (). Da Sun Microsystems har udfaset de første tre metoder (de er usikre), undersøger vi kun afbryde().

Afbryd en trådgruppe

Trådgruppe's afbryde() metode tillader en tråd at afbryde en bestemt trådgruppes tråde og undergrupper. Denne teknik ville vise sig passende i følgende scenarie: Din applikations hovedtråd opretter flere tråde, der hver udfører en enhed af arbejde. Da alle tråde skal færdiggøre deres respektive arbejdsenheder, før en tråd kan undersøge resultaterne, venter hver tråd efter at have afsluttet arbejdsenheden. Hovedtråden overvåger arbejdstilstanden. Når alle andre tråde venter, kalder hovedtråden afbryde() for at afbryde de andre tråders ventetid. Derefter kan disse tråde undersøge og behandle resultaterne. Liste 3 viser afbrydelse af trådgrupper:

Annonce 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} fang (InterruptedException e) {} // Afbryd alle metoder i samme trådgruppe som hoved // thread Thread.currentThread () .getThreadGroup () .interrupt (); }} klasse MyThread udvider tråd {public void run () {synkroniseret ("A") {System.out.println (getName () + "ved at vente."); prøv {"A" .wait (); } fange (InterruptedException e) {System.out.println (getName () + "afbrudt."); } System.out.println (getName () + "afsluttes."); }}}