Životni ciklus niti u Javi

1. Uvod

U ovom ćemo članku detaljno razmotriti osnovni koncept u Javi - životni ciklus niti.

Upotrijebit ćemo brzi ilustrirani dijagram i, naravno, praktične isječke koda da bismo bolje razumjeli ta stanja tijekom izvođenja niti.

Da biste započeli razumijevanje niti u Javi, ovaj je članak o stvaranju niti dobro mjesto za početak.

2. Multithreading u Javi

U jeziku Java, multitreading je vođen temeljnim konceptom niti. Tijekom svog životnog ciklusa niti prolaze kroz različita stanja:

3. Životni ciklus niti u Javi

The java.lang.Nit razred sadrži a statički nabroj stanja - koja definira njegova potencijalna stanja. Tijekom bilo kojeg trenutka vremena nit može biti samo u jednom od ovih stanja:

  1. NOVI - novostvorena nit koja još nije započela izvršenje
  2. RUNABLE - bilo pokrenut ili spreman za izvršenje, ali čeka na dodjelu resursa
  3. BLOKIRANO - čeka da dobije zaključavanje monitora za ulazak ili ponovni unos sinkroniziranog bloka / metode
  4. ČEKANJE - čekajući da neka druga nit izvede određenu radnju bez ikakvog vremenskog ograničenja
  5. VRIJEME_ČEKANJE - čekajući da neka druga nit izvrši određenu radnju određeno vrijeme
  6. PRESTANAK - je dovršio njegovo izvršenje

Sva su ta stanja pokrivena gornjim dijagramom; razgovarajmo sada o svakom od njih detaljno.

3.1. Novi

A NOVINit (ili rođeni Nit) je nit koja je stvorena, ali još nije pokrenuta. Ostaje u ovom stanju dok ga ne pokrenemo pomoću početak() metoda.

Sljedeći isječak koda prikazuje novostvorenu nit koja se nalazi u NOVI država:

Izvodljivo izvodljivo = novo NewState (); Navoj t = nova nit (može se pokrenuti); Log.info (t.getState ());

Budući da nismo započeli spomenutu nit, metodu t.getState () otisci:

NOVI

3.2. Izvodljivo

Kada stvorimo novu nit i pozovemo početak() metoda na tome, premješteno je iz NOVI do RANJALI država. Niti u ovom stanju ili se izvode ili su spremni za pokretanje, ali čekaju dodjelu resursa iz sustava.

U okruženju s više niti Thread-Scheduler (koji je dio JVM-a) dodijeljuje određeno vrijeme određenoj niti. Dakle, radi određeno vrijeme, a zatim prepušta kontrolu drugom RANJALI niti.

Na primjer, dodajmo t.start () metodu na naš prethodni kôd i pokušajte pristupiti njegovom trenutnom stanju:

Izvodljivo izvodljivo = novo NewState (); Navoj t = nova nit (može se pokrenuti); t.start (); Log.info (t.getState ());

Ovaj kod je najvjerojatnije za povratak rezultata kao:

RANJALI

Imajte na umu da u ovom primjeru nije uvijek zajamčeno da to vrijeme dok naša kontrola dosegne t.getState (), i dalje će biti u RANJALI država.

Može se dogoditi da je to odmah zakazao Planer niti i može završiti izvršenje. U takvim slučajevima možemo dobiti drugačiji izlaz.

3.3. Blokiran

Nit je u BLOKIRAN navedite kada trenutačno ne ispunjava uvjete. Ulazi u to stanje kada čeka zaključavanje monitora i pokušava pristupiti dijelu koda koji je zaključan nekom drugom niti.

Pokušajmo reproducirati ovo stanje:

javna klasa BlockedState {public static void main (String [] args) baca InterruptedException {Thread t1 = new Thread (new DemoThreadB ()); Tema t2 = nova nit (nova DemoThreadB ()); t1.start (); t2.start (); Navoj.spavanje (1000); Log.info (t2.getState ()); System.exit (0); }} klasa DemoThreadB implementira Runnable {@Override public void run () {commonResource (); } javna statička sinkronizirana praznina commonResource () {while (true) {// Beskonačna petlja za oponašanje teške obrade // 't1' neće napustiti ovu metodu // kada 't2' pokuša unijeti ovo}}}

U ovom kodu:

  1. Stvorili smo dvije različite niti - t1 i t2
  2. t1 pokreće i ulazi u sinkronizirano commonResource () metoda; to znači da mu može pristupiti samo jedna nit; sve ostale naredne niti koje pokušaju pristupiti ovoj metodi bit će blokirane od daljnjeg izvršavanja dok trenutna ne završi obradu
  3. Kada t1 uđe u ovu metodu, ona se čuva u beskonačnoj while petlji; ovo je samo za oponašanje teške obrade tako da sve ostale niti ne mogu ući u ovu metodu
  4. Sad kad počnemo t2, pokušava ući u commonResource () metodu, kojoj već pristupa t1, Tako, t2 će se čuvati u BLOKIRAN država

Budući da smo u ovom stanju, zovemo t2.getState () i dobiti izlaz kao:

BLOKIRAN

3.4. Čekanje

Nit je unutra ČEKANJE stanje kada čeka da neka druga nit izvrši određenu radnju. Prema JavaDocsu, bilo koja nit može ući u ovo stanje pozivanjem bilo koje od sljedeće tri metode:

  1. object.wait ()
  2. nit.join () ili
  3. LockSupport.park ()

Imajte na umu da u čekati() i pridružiti() - ne definiramo nijedno vremensko ograničenje jer je taj scenarij obrađen u sljedećem odjeljku.

Imamo zasebni vodič koji detaljno razmatra upotrebu čekati(), obavijestiti() i notifyAll ().

Za sada, pokušajmo reproducirati ovo stanje:

javna klasa WaitingState implementira Runnable {public static Thread t1; javna statička void glavna (String [] args) {t1 = nova nit (nova WaitingState ()); t1.start (); } public void run () {Thread t2 = new Thread (new DemoThreadWS ()); t2.start (); probajte {t2.join (); } catch (InterruptedException e) {Thread.currentThread (). interrupt (); Log.error ("Navoj prekinut", e); }}} klasa DemoThreadWS implementira Runnable {public void run () {try {Thread.sleep (1000); } catch (InterruptedException e) {Thread.currentThread (). interrupt (); Log.error ("Navoj prekinut", e); } Log.info (WaitingState.t1.getState ()); }}

Razgovarajmo o tome što ovdje radimo:

  1. Stvorili smo i pokrenuli t1
  2. t1 stvara a t2 i pokreće ga
  3. Dok je obrada t2 nastavlja, pozivamo t2.join (), ovo stavlja t1 u ČEKANJE država do t2 je završio izvršenje
  4. Od t1 čeka t2 da završimo, zovemo t1.getState () iz t2

Izlaz je ovdje, kao što biste očekivali:

ČEKANJE

3.5. Vremensko čekanje

Nit je unutra VRIJEME_ČEKANJE stanje kada čeka da druga nit izvrši određenu radnju u predviđenom vremenskom roku.

Prema JavaDocsu, postoji pet načina na koje se nit može staviti VRIJEME_ČEKANJE država:

  1. nit.spavanje (dugi milis)
  2. pričekaj (int timeout) ili pričekaj (int timeout, int nanos)
  3. konac.priključiti se (dugo milis)
  4. LockSupport.parkNanos
  5. LockSupport.parkUntil

Da biste pročitali više o razlikama između čekati() i spavati() na Javi, pogledajte ovaj posvećeni članak ovdje.

Za sada, pokušajmo brzo reproducirati ovo stanje:

javna klasa TimedWaitingState {javna statička void glavna (String [] args) baca InterruptedException {DemoThread obj1 = new DemoThread (); Navoj t1 = novi navoj (obj1); t1.start (); // Sljedeće spavanje dat će dovoljno vremena ThreadScheduleru // da započne obradu niti t1 Thread.sleep (1000); Log.info (t1.getState ()); }} klasa DemoThread implementira Runnable {@Override public void run () {try {Thread.sleep (5000); } catch (InterruptedException e) {Thread.currentThread (). interrupt (); Log.error ("Navoj prekinut", e); }}}

Evo, stvorili smo i započeli nit t1 koji se ulazi u stanje mirovanja s vremenom odmora od 5 sekundi; izlaz će biti:

VRIJEME_ČEKANJE

3.6. Prekinuta

Ovo je stanje mrtve niti. To je u PRESTANAK stanje kada je ili završilo izvršenje ili je abnormalno prekinuto.

Imamo namjenski članak koji govori o različitim načinima zaustavljanja niti.

Pokušajmo ovo stanje postići u sljedećem primjeru:

javna klasa TerminatedState implementira Runnable {public static void main (String [] args) baca InterruptedException {Thread t1 = new Thread (new TerminatedState ()); t1.start (); // Sljedeća metoda mirovanja dat će dovoljno vremena // niti t1 da dovrši Thread.sleep (1000); Log.info (t1.getState ()); } @Override public void run () {// Bez obrade u ovom bloku}}

Evo, dok smo započeli nit t1, sljedeća izjava Navoj.spavanje (1000) daje dovoljno vremena za t1 da dovršimo i tako nam ovaj program daje izlaz kao:

PRESTANAK

Pored stanja niti, možemo provjeriti i živ je() metoda kojom se utvrđuje je li nit živa ili nije. Na primjer, ako pozovemo živ je() metoda na ovoj niti:

Assert.assertFalse (t1.isAlive ());

Vraća se lažno. Jednostavno rečeno, nit je živa ako i samo ako ima pokrenut i još nije umro.

4. Zaključak

U ovom uputstvu naučili smo o životnom ciklusu niti u Javi. Pogledali smo svih šest država definiranih od Konac.Država nabrajati i reproducirati ih s brzim primjerima.

Iako će isječci koda dati isti izlaz na gotovo svakom stroju, u nekim iznimnim slučajevima možemo dobiti neke različite izlaze jer se ne može utvrditi točno ponašanje planera niti.

Kao i uvijek, ovdje korišteni isječci koda dostupni su na GitHubu.