In Java, un thread esiste sempre in uno qualsiasi dei seguenti stati. Questi stati sono:
- Nuovo
- Attivo
- Bloccato / In attesa
- Attesa cronometrata
- Terminato
Spiegazione dei diversi stati del thread
Nuovo: Ogni volta che viene creato un nuovo thread, è sempre nel nuovo stato. Per un thread nel nuovo stato, il codice non è stato ancora eseguito e quindi non ha ancora iniziato l'esecuzione.
Attivo: Quando un thread invoca il metodo start(), passa dal nuovo stato allo stato attivo. Lo stato attivo contiene due stati al suo interno: uno è percorribile , e l'altro lo è corsa .
Un programma che implementa il multithreading acquisisce una porzione di tempo fissa per ogni singolo thread. Ogni thread viene eseguito per un breve periodo di tempo e quando il periodo di tempo assegnato termina, il thread cede volontariamente la CPU all'altro thread, in modo che anche gli altri thread possano funzionare per il loro periodo di tempo. Ogni volta che si verifica uno scenario del genere, tutti i thread disposti a funzionare, in attesa del proprio turno, si trovano nello stato eseguibile. Nello stato eseguibile, c'è una coda in cui si trovano i thread.
Bloccato o in attesa: Ogni volta che un thread è inattivo per un periodo di tempo (non permanentemente), il thread è nello stato bloccato o nello stato di attesa.
Ad esempio, un thread (diciamo che il suo nome è A) potrebbe voler stampare alcuni dati dalla stampante. Tuttavia, allo stesso tempo, l'altro thread (diciamo che il suo nome è B) sta utilizzando la stampante per stampare alcuni dati. Pertanto, il thread A deve attendere che il thread B utilizzi la stampante. Pertanto, il thread A è nello stato bloccato. Un thread nello stato bloccato non è in grado di eseguire alcuna esecuzione e quindi non consuma mai alcun ciclo dell'unità di elaborazione centrale (CPU). Quindi, possiamo dire che il thread A rimane inattivo finché lo scheduler del thread non riattiva il thread A, che è nello stato di attesa o bloccato.
Quando il thread principale invoca il metodo join(), si dice che il thread principale è nello stato di attesa. Il thread principale attende quindi che i thread secondari completino le proprie attività. Quando i thread secondari completano il proprio lavoro, viene inviata una notifica al thread principale, che sposta nuovamente il thread dallo stato di attesa allo stato attivo.
Se ci sono molti thread nello stato di attesa o bloccato, allora è compito dello scheduler dei thread determinare quale thread scegliere e quale rifiutare, e al thread scelto viene quindi data l'opportunità di essere eseguito.
Attesa temporizzata: A volte, aspettare porta alla fame. Ad esempio, un thread (il suo nome è A) è entrato nella sezione critica di un codice e non è disposto a lasciare quella sezione critica. In uno scenario del genere, un altro thread (il suo nome è B) deve aspettare per sempre, il che porta alla fame. Per evitare tale scenario, al thread B viene assegnato uno stato di attesa temporizzato. Pertanto, il thread rimane nello stato di attesa per un periodo di tempo specifico e non per sempre. Un vero esempio di attesa temporizzata è quando invochiamo il metodo sleep() su un thread specifico. Il metodo sleep() mette il thread nello stato di attesa temporizzata. Allo scadere del tempo, il thread si riattiva e inizia la sua esecuzione da quando era stato lasciato in precedenza.
Terminato: Un thread raggiunge lo stato di terminazione per i seguenti motivi:
- Quando un thread ha terminato il suo lavoro, esiste o termina normalmente.
Un thread terminato significa che il thread non è più presente nel sistema. In altre parole, il thread è morto e non è possibile rigenerarlo (attivo dopo l'uccisione) del thread morto.
Il diagramma seguente mostra i diversi stati coinvolti nel ciclo di vita di un thread.
Implementazione degli stati dei thread
In Java, è possibile ottenere lo stato corrente di un thread utilizzando il file Thread.getState() metodo. IL java.lang.Thread.State La classe Java fornisce le costanti ENUM per rappresentare lo stato di un thread. Queste costanti sono:
rinominare la cartella in Linux
public static final Thread.State NEW
Rappresenta il primo stato di un thread che è lo stato NUOVO.
public static final Thread.State RUNNABLE
Rappresenta lo stato eseguibile. Significa che un thread è in attesa di essere eseguito nella coda.
public static final Thread.State BLOCKED
Rappresenta lo stato bloccato. In questo stato, il thread è in attesa di acquisire un lock.
public static final Thread.State WAITING
Rappresenta lo stato di attesa. Un thread passerà a questo stato quando richiama il metodo Object.wait() o il metodo Thread.join() senza timeout. Un thread nello stato di attesa attende che un altro thread completi la sua attività.
public static final Thread.State TIMED_WAITING
Rappresenta lo stato di attesa temporizzata. La differenza principale tra l'attesa e l'attesa temporizzata è il vincolo temporale. L'attesa non ha vincoli di tempo, mentre l'attesa temporizzata ha il vincolo di tempo. Un thread che invoca il metodo seguente raggiunge lo stato di attesa temporizzata.
- sonno
- partecipare con timeout
- attendere con timeout
- parkUntil
- parcoNanos
public static final Thread.State TERMINATED
Rappresenta lo stato finale di un thread terminato o inattivo. Un thread terminato significa che ha completato la sua esecuzione.
Programma Java per la dimostrazione degli stati dei thread
Il seguente programma Java mostra alcuni degli stati di un thread definito sopra.
Nome del file: 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()); } }
Produzione:
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
Spiegazione: Ogni volta che generiamo un nuovo thread, quel thread raggiunge il nuovo stato. Quando il metodo start() viene richiamato su un thread, lo scheduler del thread sposta quel thread nello stato eseguibile. Ogni volta che il metodo join() viene invocato su qualsiasi istanza del thread, il thread corrente che esegue quell'istruzione deve attendere che questo thread termini la sua esecuzione, ovvero spostare quel thread nello stato terminato. Pertanto, prima che l'istruzione print finale venga stampata sulla console, il programma invoca il metodo join() sul thread t2, facendo attendere il thread t1 mentre il thread t2 termina la sua esecuzione e quindi, il thread t2 arriva allo stato terminato o morto . Il thread t1 passa allo stato di attesa perché sta aspettando che il thread t2 termini la sua esecuzione poiché ha invocato il metodo join() sul thread t2.