Em Java, um thread sempre existe em qualquer um dos seguintes estados. Esses estados são:
- Novo
- Ativo
- Bloqueado/Aguardando
- Espera cronometrada
- Terminado
Explicação dos diferentes estados de thread
Novo: Sempre que um novo thread é criado, ele está sempre no novo estado. Para uma thread no novo estado, o código ainda não foi executado e, portanto, não iniciou sua execução.
Ativo: Quando um thread invoca o método start(), ele passa do novo estado para o estado ativo. O estado ativo contém dois estados: um é executável , e o outro é correndo .
Um programa que implementa multithreading adquire uma fatia fixa de tempo para cada thread individual. Cada thread é executado por um curto período de tempo e quando o intervalo de tempo alocado termina, o thread cede voluntariamente a CPU para o outro thread, para que os outros threads também possam ser executados durante seu intervalo de tempo. Sempre que tal cenário ocorre, todos os threads que estão dispostos a executar, aguardando sua vez de execução, ficam no estado executável. No estado executável, há uma fila onde ficam os threads.
Bloqueado ou aguardando: Sempre que um thread fica inativo por um período de tempo (não permanentemente), o thread está no estado bloqueado ou no estado de espera.
Por exemplo, um thread (digamos que seu nome seja A) pode querer imprimir alguns dados da impressora. Porém, ao mesmo tempo, o outro thread (digamos que seu nome seja B) está usando a impressora para imprimir alguns dados. Portanto, o thread A precisa aguardar o thread B usar a impressora. Assim, o thread A está no estado bloqueado. Uma thread no estado bloqueado é incapaz de realizar qualquer execução e, portanto, nunca consome nenhum ciclo da Unidade Central de Processamento (CPU). Portanto, podemos dizer que o thread A permanece ocioso até que o agendador de threads reative o thread A, que está no estado de espera ou bloqueado.
Quando o thread principal invoca o método join(), diz-se que o thread principal está em estado de espera. O thread principal então espera que os threads filhos concluam suas tarefas. Quando os threads filhos concluem seu trabalho, uma notificação é enviada ao thread principal, que novamente move o thread do estado de espera para o estado ativo.
Se houver muitos threads no estado de espera ou bloqueados, então é dever do escalonador de threads determinar qual thread escolher e qual rejeitar, e o thread escolhido terá então a oportunidade de ser executado.
Espera cronometrada: Às vezes, esperar leva à fome. Por exemplo, um thread (seu nome é A) entrou na seção crítica de um código e não está disposto a sair dessa seção crítica. Nesse cenário, outro thread (seu nome é B) tem que esperar para sempre, o que leva à fome. Para evitar tal cenário, um estado de espera cronometrado é dado ao thread B. Assim, o thread permanece no estado de espera por um período de tempo específico, e não para sempre. Um exemplo real de espera cronometrada é quando invocamos o método sleep() em um thread específico. O método sleep() coloca o thread no estado de espera cronometrada. Após o tempo acabar, o thread acorda e inicia sua execução a partir de quando saiu antes.
Terminado: Um encadeamento atinge o estado de encerramento pelos seguintes motivos:
- Quando um thread termina seu trabalho, ele existe ou termina normalmente.
Um thread encerrado significa que o thread não está mais no sistema. Em outras palavras, o thread está morto e não há como reaparecer (ativo após matar) o thread morto.
O diagrama a seguir mostra os diferentes estados envolvidos no ciclo de vida de um thread.
Implementação de estados de thread
Em Java, pode-se obter o estado atual de um thread usando o Thread.getState() método. O java.lang.Thread.State classe de Java fornece as constantes ENUM para representar o estado de um thread. Essas constantes são:
string em java
public static final Thread.State NEW
Representa o primeiro estado de um thread que é o estado NOVO.
public static final Thread.State RUNNABLE
Representa o estado executável. Significa que um thread está aguardando na fila para ser executado.
public static final Thread.State BLOCKED
Representa o estado bloqueado. Neste estado, o thread está aguardando para adquirir um bloqueio.
public static final Thread.State WAITING
Representa o estado de espera. Um thread irá para este estado quando invocar o método Object.wait() ou o método Thread.join() sem tempo limite. Um thread em estado de espera está aguardando que outro thread conclua sua tarefa.
public static final Thread.State TIMED_WAITING
Representa o estado de espera cronometrado. A principal diferença entre espera e espera cronometrada é a restrição de tempo. A espera não tem restrição de tempo, enquanto a espera cronometrada tem restrição de tempo. Um thread que invoca o método a seguir atinge o estado de espera cronometrado.
- dormir
- junte-se com tempo limite
- espere com tempo limite
- estacionar até
- parqueNanos
public static final Thread.State TERMINATED
Representa o estado final de um thread que foi encerrado ou inativo. Um thread encerrado significa que sua execução foi concluída.
Programa Java para demonstração de estados de thread
O programa Java a seguir mostra alguns dos estados de um thread definido acima.
Nome do arquivo: 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()); } }
Saída:
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ção: Sempre que geramos um novo thread, esse thread atinge o novo estado. Quando o método start() é invocado em um thread, o agendador de threads move esse thread para o estado executável. Sempre que o método join() é invocado em qualquer instância de thread, o thread atual que executa aquela instrução deve esperar que esse thread termine sua execução, ou seja, mova esse thread para o estado finalizado. Portanto, antes que a instrução print final seja impressa no console, o programa invoca o método join() na thread t2, fazendo com que a thread t1 espere enquanto a thread t2 finaliza sua execução e assim, a thread t2 chega ao estado finalizado ou morto. . O thread t1 vai para o estado de espera porque está aguardando o thread t2 terminar sua execução, pois invocou o método join() no thread t2.