Egy szál életciklusa a Java-ban

1. Bemutatkozás

Ebben a cikkben részletesen megvitatjuk a Java alapkoncepcióját - a szál életciklusát.

Gyors illusztrált diagramot és természetesen gyakorlati kódrészleteket fogunk használni, hogy jobban megértsük ezeket az állapotokat a szál végrehajtása során.

A Java szálak megértésének megkezdéséhez ez a cikk a szál létrehozásáról jó kiindulópont.

2. Többszálas Java-ban

A Java nyelvben a többszálas szálat a szál alapkoncepciója vezérli. Életciklusuk során a szálak különböző állapotokon mennek keresztül:

3. Egy szál életciklusa Java-ban

A java.lang.Thread osztály tartalmazza a statikus állapot enum - amely meghatározza annak lehetséges állapotait. Az adott időpontban a szál csak a következő állapotok egyikében lehet:

  1. ÚJ - egy újonnan létrehozott szál, amely még nem indította el a végrehajtást
  2. FUTHATÓ - vagy fut, vagy készen áll a végrehajtásra, de az erőforrások elosztására vár
  3. BLOCKED - várakozás a monitorzár megszerzésére egy szinkronizált blokk / módszer belépéséhez vagy újbóli belépéséhez
  4. VÁRÁS - arra vár, hogy egy másik szál egy adott műveletet időkorlát nélkül végezzen
  5. TIMED_WAITING - várakozás valamilyen más szálra egy adott művelet végrehajtására egy meghatározott ideig
  6. MEGSZŰNT - befejezte végrehajtását

Mindezeket az állapotokat a fenti ábra fedi le; tárgyaljuk most ezeket részletesen.

3.1. Új

A ÚJcérna (vagy egy született cérna) egy szál, amelyet létrehoztak, de még nem kezdték el. Addig marad ebben az állapotban, amíg meg nem kezdjük a Rajt() módszer.

A következő kódrészlet egy újonnan létrehozott szálat mutat, amely a ÚJ állapot:

Futható futható = new NewState (); Menet t = new Menet (futható); Log.info (t.getState ());

Mivel nem indítottuk el az említett szálat, a metódust t.getState () nyomatok:

ÚJ

3.2. Futható

Amikor létrehoztunk egy új szálat és felhívtuk a Rajt() metódus, erről elmozdult ÚJ nak nek FUTHATÓ állapot. Az ebben az állapotban lévő szálak vagy futnak, vagy készen állnak a futtatásra, de erőforrás-kiosztásra várnak a rendszerből.

Többszálas környezetben a Thread-Scheduler (amely a JVM része) fix időt rendel el minden szálhoz. Tehát egy bizonyos ideig fut, majd lemond a vezérlésről másoknak FUTHATÓ szálak.

Például tegyük hozzá t.start () metódust az előző kódunkhoz, és próbálja elérni annak jelenlegi állapotát:

Futható futható = new NewState (); Menet t = new Menet (futható); t.start (); Log.info (t.getState ());

Ez a kód legvalószínűbb a kimenetet a következő módon adja vissza:

FUTHATÓ

Vegye figyelembe, hogy ebben a példában nem mindig garantált, hogy mire az irányításunk eléri t.getState (), akkor is a FUTHATÓ állapot.

Előfordulhat, hogy azonnal ütemezte a Menetütemező és befejezheti a végrehajtást. Ilyen esetekben más kimenetet kaphatunk.

3.3. Zárolt

Egy szál van a ZÁROLT állítsa be, mikor nem futtatható jelenleg. Akkor lép ebbe az állapotba, amikor monitorzárra vár, és megpróbál hozzáférni egy olyan kódrészhez, amelyet valamilyen más szál zárolt.

Próbáljuk meg reprodukálni ezt az állapotot:

public class BlockedState {public static void main (String [] args) dobja az InterruptedException {Thread t1 = new Thread (new DemoThreadB ()); Szál t2 = új szál (új DemoThreadB ()); t1.start (); t2.start (); Szál.alszik (1000); Log.info (t2.getState ()); System.exit (0); }} osztály DemoThreadB implementálja a Runnable {@Override public void run () {commonResource (); } public static synchronized void commonResource () {while (true) {// A végtelen ciklus a nehéz feldolgozás utánzásához // A 't1' nem hagyja el ezt a módszert // amikor a 't2' megpróbálja ezt megadni}}}

Ebben a kódban:

  1. Két különböző szálat hoztunk létre - t1 és t2
  2. t1 elindul és belép a szinkronizáltba commonResource () módszer; ez azt jelenti, hogy csak egy szál férhet hozzá; az összes további szálat, amely megpróbálja elérni ezt a módszert, blokkoljuk a további végrehajtástól, amíg a jelenlegi befejezi a feldolgozást
  3. Mikor t1 belép ebbe a módszerbe, a végtelen, míg a hurokban tartják; ez csak a nehéz feldolgozás utánzása, hogy az összes többi szál ne léphessen be ebbe a módszerbe
  4. Most, amikor elkezdjük t2, megpróbálja beírni a commonResource () módszer, amelyhez már hozzáfér a t1, így, t2 a ZÁROLT állapot

Ebben az állapotban hívjuk t2.getState () és kapja meg a kimenetet:

ZÁROLT

3.4. Várakozás

Egy szál van VÁRAKOZÁS állapot, amikor egy másik szálra vár egy adott művelet végrehajtására. A JavaDocs szerint bármely szál beléphet ebbe az állapotba a következő három módszer bármelyikének meghívásával:

  1. object.wait ()
  2. thread.join () vagy
  3. LockSupport.park ()

Vegye figyelembe, hogy a várjon() és csatlakozik() - nem definiálunk időkorlátot, mivel a forgatókönyv a következő szakaszban szerepel.

Van egy külön bemutatónk, amely részletesen tárgyalja a használatát várjon(), értesít () és értesítMinden ().

Most próbáljuk meg reprodukálni ezt az állapotot:

public class WaitingState megvalósítja Runnable {public static Thread t1; public static void main (String [] args) {t1 = új szál (új WaitingState ()); t1.start (); } public void run () {szál t2 = új szál (új DemoThreadWS ()); t2.start (); próbáld meg a {t2.csatlakozz (); } catch (InterruptedException e) {Szál.currentThread (). megszakítás (); Log.error ("A szál megszakadt", e); }}} osztály DemoThreadWS megvalósítja a Runnable {public void run () {try {Thread.sleep (1000); } catch (InterruptedException e) {Szál.currentThread (). megszakítás (); Log.error ("A szál megszakadt", e); } Log.info (WaitingState.t1.getState ()); }}

Beszéljük meg, mit csinálunk itt:

  1. Létrehoztuk és elindítottuk a t1
  2. t1 létrehoz egy t2 és elindítja
  3. Míg a feldolgozása t2 folytatja, hívjuk t2.csatlakozzon (), ez hozza t1 ban ben VÁRAKOZÁS állapotáig t2 befejezte a végrehajtást
  4. Mivel t1 vár t2 hogy teljes legyen, hívunk t1.getState () tól től t2

A kimenet itt az, amire számíthat:

VÁRAKOZÁS

3.5. Időzített várakozás

Egy szál van TIMED_WAITING állapot, amikor egy másik szálra vár egy adott művelet végrehajtása meghatározott időn belül.

A JavaDocs szerint ötféle módon lehet szálat felhelyezni TIMED_WAITING állapot:

  1. menet.alszik (hosszú millis)
  2. várakozás (időtúllépés) vagy várakozás (int timeout, int nanos)
  3. szál.csatlakozzon (hosszú millis)
  4. LockSupport.parkNanos
  5. LockSupport.parkUntil

Ha többet szeretne megtudni a különbségekről várjon() és alvás() a Java-ban, nézze meg ezt a dedikált cikket itt.

Most próbáljuk meg gyorsan reprodukálni ezt az állapotot:

public class TimedWaitingState {public static void main (String [] args) dob InterruptedException {DemoThread obj1 = new DemoThread (); Szál t1 = új szál (obj1); t1.start (); // A következő alvás elegendő időt biztosít a ThreadScheduler számára // a t1 szál feldolgozásának megkezdéséhez Thread.sleep (1000); Log.info (t1.getState ()); }} osztály DemoThread futtatja a Runnable {@Orride public void run () {try {Thread.sleep (5000); } catch (InterruptedException e) {Szál.currentThread (). megszakítás (); Log.error ("A szál megszakadt", e); }}}

Itt hoztunk létre és indítottunk el egy szálat t1 amely alvási állapotba kerül 5 másodperces időtúllépési periódussal; a kimenet a következő lesz:

TIMED_WAITING

3.6. Megszűnt

Ez egy holt szál állapota. Ebben van MEGSZŰNT állapotot, amikor befejezte a végrehajtást, vagy rendellenesen szüntették meg.

Van egy dedikált cikkünk, amely a szál leállításának különböző módjait tárgyalja.

Próbáljuk meg elérni ezt az állapotot a következő példában:

a TerminedState nyilvános osztály megvalósítja a Runnable {public static void main (String [] args) dob InterruptedException {Thread t1 = new Thread (new TerminatedState ()); t1.start (); // A következő alvási módszer elegendő időt ad a // t1 szálnak a Thread.sleep (1000) befejezéséhez; Log.info (t1.getState ()); } @Orride public void run () {// Nincs feldolgozás ebben a blokkban}}

Itt, amíg elkezdtük a szálat t1, a következő állítás Thread.sleep (1000) elegendő időt ad arra t1 befejezéséhez, így ez a program a következőképpen adja meg a kimenetet:

MEGSZŰNT

A szálállapot mellett ellenőrizhetjük a életben van() módszer annak megállapítására, hogy a szál él-e vagy sem. Például, ha a életben van() módszer ezen a szálon:

Assert.assertFalse (t1.isAlive ());

Visszatér hamis. Leegyszerűsítve: egy szál akkor és akkor él, ha van még nem halt meg.

4. Következtetés

Ebben az oktatóanyagban megismerkedtünk egy szál életciklusával a Java-ban. Megnéztük mind a hat állapotot, amelyet definiált Menet. Állam enum és gyors példákkal reprodukálta őket.

Bár a kódrészletek szinte minden gépben ugyanazt a kimenetet adják, néhány kivételes esetben előfordulhat, hogy különböző kimeneteket kapunk, mivel a Thread Scheduler pontos viselkedése nem határozható meg.

És mint mindig, az itt használt kódrészletek is elérhetők a GitHubon.