logo

Ciclul de viață al unui fir (stările firului)

În Java, un fir de execuție există întotdeauna în oricare dintre următoarele stări. Aceste stări sunt:

  1. Nou
  2. Activ
  3. Blocat/Aștept
  4. Așteptare cronometrată
  5. Terminat

Explicația diferitelor stări ale firelor

Nou: Ori de câte ori este creat un fir nou, acesta este întotdeauna în starea nouă. Pentru un fir în noua stare, codul nu a fost încă rulat și, prin urmare, nu și-a început execuția.

Activ: Când un fir de execuție invocă metoda start(), acesta trece de la starea nouă la starea activă. Starea activă conține două stări în ea: una este rulabil , iar celălalt este alergare .

    Rugabil:Un fir, care este gata de rulare, este mutat apoi în starea de rulat. În starea de rulare, firul de execuție poate rula sau poate fi gata de rulare în orice moment dat. Este datoria programatorului de fir să furnizeze timpul de rulare al firului, adică să mute firul în starea de rulare.
    Un program care implementează multithreading dobândește o perioadă fixă ​​de timp pentru fiecare fir individual. Fiecare fir de execuție rulează pentru o perioadă scurtă de timp, iar când intervalul de timp alocat se termină, firul de execuție renunță voluntar CPU celuilalt fir, astfel încât celelalte fire să poată rula și pe intervalul lor de timp. Ori de câte ori apare un astfel de scenariu, toate acele fire care sunt dispuse să ruleze, așteaptă să le fie rândul să ruleze, se află în starea de rulare. În starea rulabilă, există o coadă în care se află firele.Alergare:Când firul de execuție primește procesorul, acesta trece de la starea de rulare la starea de rulare. În general, cea mai frecventă schimbare a stării unui fir este de la rulabil la rulabil și din nou înapoi la rulabil.

Blocat sau în așteptare: Ori de câte ori un fir este inactiv pentru o perioadă de timp (nu permanent), atunci fie firul este în starea blocată, fie în starea de așteptare.

De exemplu, un fir de execuție (să spunem că numele său este A) poate dori să imprime unele date de la imprimantă. Totuși, în același timp, celălalt thread (să spunem că numele său este B) folosește imprimanta pentru a tipări unele date. Prin urmare, firul A trebuie să aștepte ca firul B să folosească imprimanta. Astfel, firul A este în starea blocată. Un fir de execuție în starea blocată nu poate efectua nicio execuție și, prin urmare, nu consumă niciodată niciun ciclu al Unității Centrale de Procesare (CPU). Prin urmare, putem spune că firul A rămâne inactiv până când planificatorul de fire reactivează firul A, care este în starea de așteptare sau blocat.

Atunci când firul principal invocă metoda join(), se spune că firul principal este în starea de așteptare. Firul principal așteaptă apoi ca firele secundare să își finalizeze sarcinile. Când firele secundare își termină treaba, se trimite o notificare către firul principal, care mută din nou firul de execuție de la starea de așteptare la starea activă.

Dacă există o mulțime de fire de execuție în starea de așteptare sau blocată, atunci este datoria planificatorului de fire să determine ce fir să aleagă și pe care să îl respingă, iar firul ales are apoi posibilitatea de a rula.

Așteptare temporizată: Uneori, așteptarea duce la foame. De exemplu, un fir (numele său este A) a intrat în secțiunea critică a unui cod și nu este dispus să părăsească acea secțiune critică. Într-un astfel de scenariu, un alt fir (numele său este B) trebuie să aștepte pentru totdeauna, ceea ce duce la foame. Pentru a evita un astfel de scenariu, firului B i se acordă o stare de așteptare temporizată. Astfel, firul se află în starea de așteptare pentru o anumită perioadă de timp și nu pentru totdeauna. Un exemplu real de așteptare temporizată este atunci când invocăm metoda sleep() pe un anumit fir. Metoda sleep() pune firul de execuție în starea de așteptare temporizată. După expirarea timpului, firul se trezește și își începe execuția de când a plecat mai devreme.

Terminat: Un fir ajunge în starea de terminare din următoarele motive:

  • Când un fir și-a terminat treaba, atunci acesta există sau se termină în mod normal.
  • Terminare anormala:Apare atunci când unele evenimente neobișnuite, cum ar fi o excepție netratată sau o eroare de segmentare.

Un fir terminat înseamnă că firul nu mai este în sistem. Cu alte cuvinte, firul este mort și nu există nicio modalitate de a renaște (activ după ucidere) firul mort.

Următoarea diagramă arată diferitele stări implicate în ciclul de viață al unui fir.

Ciclul de viață al firului Java

Implementarea stărilor de fir

În Java, se poate obține starea curentă a unui fir folosind Thread.getState() metodă. The java.lang.Thread.State clasa Java furnizează constantele ENUM pentru a reprezenta starea unui fir. Aceste constante sunt:

constructori în java
 public static final Thread.State NEW 

Reprezintă prima stare a unui fir care este starea NOUĂ.

 public static final Thread.State RUNNABLE 

Reprezintă starea care poate fi rulată. Înseamnă că un fir așteaptă în coadă să ruleze.

 public static final Thread.State BLOCKED 

Reprezintă starea blocată. În această stare, firul așteaptă să obțină o blocare.

 public static final Thread.State WAITING 

Reprezintă starea de așteptare. Un fir de execuție va ajunge în această stare atunci când invocă metoda Object.wait() sau metoda Thread.join() fără timeout. Un fir în starea de așteptare așteaptă ca un alt fir să își finalizeze sarcina.

 public static final Thread.State TIMED_WAITING 

Reprezintă starea de așteptare temporizată. Principala diferență dintre așteptarea și așteptarea temporizată este constrângerea de timp. Așteptarea nu are constrângere de timp, în timp ce așteptarea temporizată are constrângere de timp. Un fir care invocă următoarea metodă ajunge în starea de așteptare temporizată.

  • dormi
  • alăturați-vă cu timeout
  • așteptați cu timeout
  • parkUntil
  • parkNanos
 public static final Thread.State TERMINATED 

Reprezintă starea finală a unui fir care este încheiat sau mort. Un fir terminat înseamnă că și-a încheiat execuția.

Program Java pentru demonstrarea stărilor firelor

Următorul program Java arată unele dintre stările unui fir definit mai sus.

Nume de fișier: ThreadState.java

 // ABC class implements the interface Runnable class ABC implements Runnable { public void run() { // try-catch block try { // moving thread t2 to the state timed waiting Thread.sleep(100); } catch (InterruptedException ie) { ie.printStackTrace(); } System.out.println('The state of thread t1 while it invoked the method join() on thread t2 -'+ ThreadState.t1.getState()); // try-catch block try { Thread.sleep(200); } catch (InterruptedException ie) { ie.printStackTrace(); } } } // ThreadState class implements the interface Runnable public class ThreadState implements Runnable { public static Thread t1; public static ThreadState obj; // main method public static void main(String argvs[]) { // creating an object of the class ThreadState obj = new ThreadState(); t1 = new Thread(obj); // thread t1 is spawned // The thread t1 is currently in the NEW state. System.out.println('The state of thread t1 after spawning it - ' + t1.getState()); // invoking the start() method on // the thread t1 t1.start(); // thread t1 is moved to the Runnable state System.out.println('The state of thread t1 after invoking the method start() on it - ' + t1.getState()); } public void run() { ABC myObj = new ABC(); Thread t2 = new Thread(myObj); // thread t2 is created and is currently in the NEW state. System.out.println('The state of thread t2 after spawning it - '+ t2.getState()); t2.start(); // thread t2 is moved to the runnable state System.out.println('the state of thread t2 after calling the method start() on it - ' + t2.getState()); // try-catch block for the smooth flow of the program try { // moving the thread t1 to the state timed waiting Thread.sleep(200); } catch (InterruptedException ie) { ie.printStackTrace(); } System.out.println('The state of thread t2 after invoking the method sleep() on it - '+ t2.getState() ); // try-catch block for the smooth flow of the program try { // waiting for thread t2 to complete its execution t2.join(); } catch (InterruptedException ie) { ie.printStackTrace(); } System.out.println('The state of thread t2 when it has completed it's execution - ' + t2.getState()); } } 

Ieșire:

 The state of thread t1 after spawning it - NEW The state of thread t1 after invoking the method start() on it - RUNNABLE The state of thread t2 after spawning it - NEW the state of thread t2 after calling the method start() on it - RUNNABLE The state of thread t1 while it invoked the method join() on thread t2 -TIMED_WAITING The state of thread t2 after invoking the method sleep() on it - TIMED_WAITING The state of thread t2 when it has completed it's execution - TERMINATED 

Explicaţie: Ori de câte ori generăm un nou thread, acel thread atinge noua stare. Când metoda start() este invocată pe un fir de execuție, planificatorul firului de execuție mută acel fir de execuție în starea rulabilă. Ori de câte ori metoda join() este invocată pe orice instanță de fir, firul de execuție curent care execută acea instrucțiune trebuie să aștepte ca acest fir să își termine execuția, adică să mute acel fir de execuție în starea terminată. Prin urmare, înainte ca instrucțiunea finală de imprimare să fie tipărită pe consolă, programul invocă metoda join() pe firul t2, făcând firul t1 să aștepte în timp ce firul t2 își termină execuția și astfel, firul t2 ajunge la starea terminată sau mort. . Thread-ul t1 trece în starea de așteptare deoarece așteaptă ca firul t2 să-și termine execuția, deoarece a invocat metoda join() pe firul t2.