Java 101: Razumijevanje Java niti, 4. dio: Grupe niti, volatilnost i lokalne varijable niti

Ovomjesečna Java 101 zaključuje seriju niti usredotočujući se na skupine niti, volatilnost, lokalne varijable niti, tajmere i ThreadDeathklasu.

Razumijevanje Java niti - pročitajte cijelu seriju

  • Dio 1: Upoznavanje niti i pokretačkih programa
  • Dio 2: Sinkronizacija niti
  • Dio 3: Zakazivanje niti, čekanje / obavještavanje i prekidanje niti
  • Dio 4: Skupine niti, volatilnost, lokalne varijable niti, mjerači vremena i odumiranje niti

Skupine niti

U programu mrežnog poslužitelja jedna nit čeka i prihvaća zahtjeve klijentskih programa za izvršavanje, na primjer, transakcija baze podataka ili složenih izračuna. Nit obično stvara novu nit za obradu zahtjeva. Ovisno o volumenu zahtjeva, istovremeno može biti prisutno mnogo različitih niti, što otežava upravljanje nitima. Kako bi pojednostavili upravljanje nitima, programi organiziraju svoje niti s grupama niti - java.lang.ThreadGroupobjektima koji grupiraju povezane objekte niti Thread(i Threadpotklase). Na primjer, vaš program može ThreadGroupgrupirati sve niti ispisa u jednu skupinu.

Napomena: Da bi rasprava bila jednostavna, pozivam se na skupine niti kao da organiziraju niti. U stvarnosti, skupine niti organiziraju Thread(i Threadpotklasu) objekte povezane s nitima.

Java zahtijeva svaku nit i svaku skupinu niti - osim korijenske skupine niti system- da bi se pridružila nekoj drugoj grupi niti. Taj raspored dovodi do hijerarhijske strukture grupa niti, što donja slika ilustrira u kontekstu aplikacije.

Na vrhu strukture lika nalazi se systemskupina niti. JVM stvorena systemgrupa organizira JVM niti koje se bave finalizacijom objekata i ostalim sistemskim zadacima i služi kao korijenska grupa niti hijerarhijske strukture niti skupine aplikacija. Neposredno ispod systemje maingrupa niti koju je kreirao JVM , a to je systemgrupa podteta (skraćeno, podskupina). mainsadrži barem jednu nit - glavnu nit stvorenu JVM-om koja izvršava upute bajt-koda u main()metodi.

Ispod maingrupe nalaze se podskupine subgroup 1i subgroup 2podskupine i aplikacije kreirane podgrupe (koje aplikacija na slici stvara). Nadalje, subgroup 1skupina tri aplikacija kreirana teme: thread 1, thread 2i thread 3. Za razliku od toga, subgroup 2grupa je jedan program stvorio nit: my thread.

Sad kad znate osnove, krenimo s izradom grupa niti.

Stvorite grupe niti i pridružite niti s tim skupinama

Dokumentacija ThreadGroupSDK klase otkriva dva konstruktora: ThreadGroup(String name)i ThreadGroup(ThreadGroup parent, String name). Oba konstruktora stvaraju grupu niti i daju joj ime, kako nameparametar navodi. Konstruktori se razlikuju u odabiru skupine nit koja služi kao nadređena novostvorenoj grupi niti. Svaka grupa niti, osim system, mora imati nadređenu skupinu niti. Jer ThreadGroup(String name), roditelj je grupa niti koja poziva ThreadGroup(String name). Kao primjer, ako glavna nit poziva ThreadGroup(String name), novostvorena grupa niti ima nadređenu grupu glavne niti - main. Jer ThreadGroup(ThreadGroup parent, String name), roditelj je grupa koja se parentreferira. Sljedeći kod pokazuje kako koristiti ove konstruktore za stvaranje para grupa niti:

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

U gornjem kodu glavna nit stvara dvije skupine niti: Ai B. Prvo, glavna nit stvara Apozivanjem ThreadGroup(String name). U tg1roditelj -referenced konac grupe je mainjer mainje glavna nit je nit skupina. Drugo, glavna nit stvara Bpozivanjem ThreadGroup(ThreadGroup parent, String name). U tg2roditelj -referenced nit skupine je Azato tg1„s referenca prolazi kao argument ThreadGroup (tg1, "B")i Asuradnika s tg1.

Savjet: Nakon što više ne trebate hijerarhiju ThreadGroupobjekata, poziva ThreadGroup„s void destroy()metodom putem odnosu na ThreadGroupobjekt na vrhu tog hijerarhije. Ako gornjem ThreadGroupobjektu i svim objektima podskupine nedostaju objekti niti, destroy()priprema te objekte niti grupa za prikupljanje smeća. Inače, destroy()baca IllegalThreadStateExceptionpredmet. Međutim, dok ne poništite referencu na gornji ThreadGroupobjekt (pod pretpostavkom da varijabla polja sadrži tu referencu), sakupljač smeća ne može prikupiti taj objekt. Pozivom na vrh objekt, možete odrediti da li se prethodni poziv je napravljen na destroy()način pozivom ThreadGroup„s boolean isDestroyed()metodu. Ta metoda vraća true ako je hijerarhija grupe niti bila uništena.

Sami po sebi, skupine niti su beskorisne. Da bi bili od koristi, moraju grupirati niti. Niti grupirate u skupine niti prosljeđivanjem ThreadGroupreferenci odgovarajućim Threadkonstruktorima:

ThreadGroup tg = new ThreadGroup ("subgroup 2"); Thread t = new Thread (tg, "my thread");

Gornji kod prvo stvara subgroup 2grupu s mainnadređenom grupom. (Pretpostavljam da glavna nit izvršava kôd.) Kôd sljedeći stvara my threadThreadobjekt u subgroup 2grupi.

Sada, kreirajmo aplikaciju koja stvara hijerarhijsku strukturu niti-figure naše figure:

Popis 1. ThreadGroupDemo.java

// ThreadGroupDemo.java class ThreadGroupDemo { public static void main (String [] args) { ThreadGroup tg = new ThreadGroup ("subgroup 1"); Thread t1 = new Thread (tg, "thread 1"); Thread t2 = new Thread (tg, "thread 2"); Thread t3 = new Thread (tg, "thread 3"); tg = new ThreadGroup ("subgroup 2"); Thread t4 = new Thread (tg, "my thread"); tg = Thread.currentThread ().getThreadGroup (); int agc = tg.activeGroupCount (); System.out.println ("Active thread groups in " + tg.getName () + " thread group: " + agc); tg.list (); } }

ThreadGroupDemokreira odgovarajuću grupu niti i objekte niti kako bi zrcalili ono što vidite na gornjoj slici. Da bi dokazao da su grupe subgroup 1and i jedine podskupine, čini sljedeće:subgroup 2mainThreadGroupDemo

  1. Dohvaća referenca na glavnoj niti je ThreadGroupobjekt pozivom Thread„s statičku currentThread()metodu (koja vraća referencu na glavnoj niti je Threadobjekt), a potom Thread” s ThreadGroup getThreadGroup()metodom.
  2. Pozivi ThreadGroup„s int activeGroupCount()metodom na samo-vratio ThreadGrouposvrtom na povratak procjenu aktivnih skupina unutar navoja grupe glavna nit-a.
  3. Pozivi ThreadGroup„s String getName ()metodom da se vrati ime nit grupe glavna nit-a.
  4. Pozivi ThreadGroup„s void list ()metodom za ispis na standardnim detaljima izlaz uređaja na konac skupine glavna nit i svim podskupinama.

Kada se pokrene, ThreadGroupDemoprikazuje sljedeći izlaz:

Active thread groups in main thread group: 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] Thread[thread 1,5,subgroup 1] Thread[thread 2,5,subgroup 1] Thread[thread 3,5,subgroup 1] java.lang.ThreadGroup[name=subgroup 2,maxpri=10] Thread[my thread,5,subgroup 2]

Izlaz koji počinje s Threadrezultatima list()„s unutarnje pozive na Thread” s toString()metodom, izlazni format sam opisao u 1. dio, uz taj izlaz, vidite izlaz s početkom java.lang.ThreadGroup. Taj izlaz identificira ime skupine niti nakon čega slijedi njezin maksimalni prioritet.

Grupe prioriteta i niti

Maksimalni prioritet grupe niti najveći je prioritet koji može postići bilo koja od njegovih niti. Razmotrite gore spomenuti program mrežnog poslužitelja. Unutar tog programa nit čeka i prihvaća zahtjeve klijentskih programa. Prije nego što to učini, nit čekanja / prihvaćanja-zahtjeva može prvo stvoriti grupu niti s maksimalnim prioritetom odmah ispod prioriteta te niti. Kasnije, kada stigne zahtjev, nit čekanja / prihvaćanja zahtjeva kreira novu nit koja odgovara na zahtjev klijenta i dodaje novu nit u prethodno stvorenu grupu niti. Prioritet nove niti automatski se spušta na maksimum grupe niti. Na taj način nit čekanja / prihvaćanja zahtjeva češće reagira na zahtjeve jer se češće izvodi.

Java svakoj skupini niti dodjeljuje maksimalni prioritet. Kada kreirate grupu, Java taj prioritet dobiva od nadređene grupe. Koristite ThreadGroupje void setMaxPriority(int priority)metoda za naknadno postavljanje maksimalne prioritet. Sve niti koje dodate grupi nakon postavljanja maksimalnog prioriteta ne mogu imati prioritet koji premašuje maksimum. Bilo koja nit s većim prioritetom automatski se smanjuje kad se pridruži grupi niti. Međutim, ako koristite setMaxPriority(int priority)za snižavanje maksimalnog prioriteta grupe, sve niti dodane u grupu prije poziva te metode zadržavaju svoje izvorne prioritete. Na primjer, ako dodate nit prioriteta 8 grupi s maksimalnim prioritetom 9, a zatim spustite maksimalni prioritet te grupe na 7, nit prioriteta 8 ostaje na prioritetu 8. U bilo kojem trenutku možete odrediti skup nitis maksimalno prioritet pozivom ThreadGroup„sint getMaxPriority()metoda. Da bih demonstrirao prioritet i skupine niti, napisao sam MaxPriorityDemo:

Popis 2. MaxPriorityDemo.java

// MaxPriorityDemo.java class MaxPriorityDemo { public static void main (String [] args) { ThreadGroup tg = new ThreadGroup ("A"); System.out.println ("tg maximum priority = " + tg.getMaxPriority ()); Thread t1 = new Thread (tg, "X"); System.out.println ("t1 priority = " + t1.getPriority ()); t1.setPriority (Thread.NORM_PRIORITY + 1); System.out.println ("t1 priority after setPriority() = " + t1.getPriority ()); tg.setMaxPriority (Thread.NORM_PRIORITY - 1); System.out.println ("tg maximum priority after setMaxPriority() = " + tg.getMaxPriority ()); System.out.println ("t1 priority after setMaxPriority() = " + t1.getPriority ()); Thread t2 = new Thread (tg, "Y"); System.out.println ("t2 priority = " + t2.getPriority ()); t2.setPriority (Thread.NORM_PRIORITY); System.out.println ("t2 priority after setPriority() = " + t2.getPriority ()); } }

Kada se pokrene, MaxPriorityDemodaje sljedeći izlaz:

tg maximum priority = 10 t1 priority = 5 t1 priority after setPriority() = 6 tg maximum priority after setMaxPriority() = 4 t1 priority after setMaxPriority() = 6 t2 priority = 4 t2 priority after setPriority() = 4

Skupina niti A(koja tgreferencira) započinje s najvišim prioritetom (10) kao svojim maksimumom. Nit X, čiji se Threadobjekt t1odnosi, pridružuje se grupi i prima 5 kao prioritet. Mijenjamo prioritet te niti na 6, što uspijeva jer je 6 manje od 10. Nakon toga pozivamo setMaxPriority(int priority)da smanjimo maksimalni prioritet grupe na 4. Iako nit Xostaje na prioritetu 6, novo dodana Ynit prima 4 kao prioritet. Napokon, pokušaj povećanja Yprioriteta niti na 5 ne uspijeva jer je 5 veće od 4.

Napomena:setMaxPriority(int priority) automatski prilagođava maksimalni prioritet podskupina grupe niti.

Osim što koristite skupine niti za ograničavanje prioriteta niti, druge zadatke možete ostvariti pozivanjem različitih ThreadGroupmetoda koje se primjenjuju na nit svake grupe. Metode uključuju void suspend(), void resume(), void stop(), i void interrupt(). Budući da je Sun Microsystems zastario prve tri metode (one nisu sigurne), ispitujemo samo interrupt().

Prekini grupu niti

ThreadGroup's interrupt()metoda omogućava niti da prekida niti i podskupine određene skupine niti. Ova bi se tehnika pokazala prikladnom u sljedećem scenariju: Glavna nit vaše aplikacije stvara više niti koje svaka izvodi jedinicu rada. Budući da sve niti moraju dovršiti svoje radne jedinice prije nego što bilo koja nit može ispitati rezultate, svaka nit čeka nakon završetka svoje radne jedinice. Glavna nit prati radno stanje. Jednom kada sve ostale niti čekaju, glavna nit poziva interrupt()da prekine čekanje ostalih niti. Tada te niti mogu ispitati i obraditi rezultate. Popis 3 pokazuje prekid grupe niti:

Popis 3. InterruptThreadGroup.java

// InterruptThreadGroup.java class InterruptThreadGroup { public static void main (String [] args) { MyThread mt = new MyThread (); mt.setName ("A"); mt.start (); mt = new MyThread (); mt.setName ("B"); mt.start (); try { Thread.sleep (2000); // Wait 2 seconds } catch (InterruptedException e) { } // Interrupt all methods in the same thread group as the main // thread Thread.currentThread ().getThreadGroup ().interrupt (); } } class MyThread extends Thread { public void run () { synchronized ("A") { System.out.println (getName () + " about to wait."); try { "A".wait (); } catch (InterruptedException e) { System.out.println (getName () + " interrupted."); } System.out.println (getName () + " terminating."); } } }