Ciclo de vida de um segmento em Java

Ciclo de vida de um segmento em Java

 

1. Introdução

Neste artigo, discutiremos em detalhes um conceito central em Java - o ciclo de vida de um thread.

Usaremos um diagrama ilustrado rápido e, é claro, snippets de código práticos para entender melhor esses estados durante a execução do thread.

Para começar a entender Threads em Java,this article na criação de um thread é um bom lugar para começar.

2. Multithreading em Java

In the Java language, multithreading is driven by the core concept of a Thread. Durante seu ciclo de vida, os threads passam por vários estados:

image

3. Ciclo de vida de um segmento em Java

A classejava.lang.Thread contém umstatic State enum – que define seus estados potenciais. Durante qualquer ponto do tempo, o encadeamento pode estar apenas em um destes estados:

  1. NEW – thread recém-criado que ainda não iniciou a execução

  2. RUNNABLE – em execução ou pronto para execução, mas está aguardando a alocação de recursos

  3. BLOCKED – esperando para adquirir um bloqueio de monitor para entrar ou reentrar em um bloco / método sincronizado

  4. WAITING – esperando por algum outro thread para realizar uma ação particular sem qualquer limite de tempo

  5. TIMED_WAITING – esperando por algum outro thread para realizar uma ação específica por um período especificado

  6. TERMINATED – concluiu sua execução

Todos esses estados são abordados no diagrama acima; vamos agora discutir cada um deles em detalhes.

3.1. New

A NEW Thread (or a Born Thread) is a thread that’s been created but not yet started. Ele permanece neste estado até que o iniciemos usando o métodostart().

O seguinte snippet de código mostra um thread recém-criado que está no estadoNEW:

Runnable runnable = new NewState();
Thread t = new Thread(runnable);
Log.info(t.getState());

Como não iniciamos o segmento mencionado, o métodot.getState() imprime:

NEW

3.2. Executável

Quando criamos um novo thread e chamamos o métodostart() nele, ele é movido do estadoNEW paraRUNNABLE. Threads in this state are either running or ready to run, but they’re waiting for resource allocation from the system.

Em um ambiente multithread, o Agendador de Threads (que faz parte da JVM) aloca uma quantidade fixa de tempo para cada thread. Portanto, ele é executado por um determinado período de tempo e, a seguir, cede o controle a outros encadeamentosRUNNABLE.

Por exemplo, vamos adicionar o métodot.start() ao nosso código anterior e tentar acessar seu estado atual:

Runnable runnable = new NewState();
Thread t = new Thread(runnable);
t.start();
Log.info(t.getState());

Este código émost likely para retornar a saída como:

RUNNABLE

Observe que, neste exemplo, nem sempre é garantido que, quando nosso controle atingirt.getState(), ele ainda estará no estadoRUNNABLE.

Pode acontecer que tenha sido imediatamente agendado pelosThread-Schedulere termine a execução. Nesses casos, podemos obter uma saída diferente.

3.3. Bloqueado

Um encadeamento está no estadoBLOCKED quando atualmente não está qualificado para execução. It enters this state when it is waiting for a monitor lock and is trying to access a section of code that is locked by some other thread.

Vamos tentar reproduzir este estado:

public class BlockedState {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new DemoThreadB());
        Thread t2 = new Thread(new DemoThreadB());

        t1.start();
        t2.start();

        Thread.sleep(1000);

        Log.info(t2.getState());
        System.exit(0);
    }
}

class DemoThreadB implements Runnable {
    @Override
    public void run() {
        commonResource();
    }

    public static synchronized void commonResource() {
        while(true) {
            // Infinite loop to mimic heavy processing
            // 't1' won't leave this method
            // when 't2' try to enters this
        }
    }
}

Neste código:

  1. Criamos dois threads diferentes -t1 et2

  2. t1 inicia e entra no métodocommonResource() sincronizado; isso significa que apenas um thread pode acessá-lo; todas as outras threads subsequentes que tentarem acessar este método serão bloqueadas para a execução posterior até que a atual termine o processamento

  3. Quandot1 entra neste método, ele é mantido em loop while infinito; isso é apenas para imitar o processamento pesado para que todos os outros threads não possam entrar neste método

  4. Agora, quando iniciamost2, ele tenta inserir o métodocommonResource(), que já está sendo acessado port1,, portanto,t2 será mantido no estadoBLOCKED

Estando neste estado, chamamost2.getState()e obtemos a saída como:

BLOCKED

3.4. Esperando

A thread is in WAITING state when it’s waiting for some other thread to perform a particular action.According to JavaDocs, qualquer thread pode entrar neste estado chamando qualquer um dos três métodos a seguir:

  1. object.wait()

  2. thread.join() ou

  3. LockSupport.park()

Observe que emwait()ejoin() - não definimos nenhum período de tempo limite, pois esse cenário é coberto na próxima seção.

Temosa separate tutorial que discute em detalhes o uso dewait(),notify()enotifyAll().

Por enquanto, vamos tentar reproduzir este estado:

public class WaitingState implements Runnable {
    public static Thread t1;

    public static void main(String[] args) {
        t1 = new Thread(new WaitingState());
        t1.start();
    }

    public void run() {
        Thread t2 = new Thread(new DemoThreadWS());
        t2.start();

        try {
            t2.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }
    }
}

class DemoThreadWS implements Runnable {
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }

        Log.info(WaitingState.t1.getState());
    }
}

Vamos discutir o que estamos fazendo aqui:

  1. Nós criamos e iniciamos ot1

  2. t1 cria umt2e inicia

  3. Enquanto o processamento det2 continua, chamamost2.join(), isso colocat1 no estadoWAITING até quet2 termine a execução

  4. Comot1 está esperandot2 terminar, estamos chamandot1.getState() det2

A saída aqui é, como você esperava:

WAITING

3.5. Espera cronometrada

Um encadeamento está no estadoTIMED_WAITING quando está esperando que outro encadeamento execute uma ação específica dentro de um período de tempo estipulado.

According to JavaDocs, existem cinco maneiras de colocar um encadeamento no estadoTIMED_WAITING:

  1. thread.sleep(long millis)

  2. wait(int timeout) ouwait(int timeout, int nanos)

  3. thread.join(long milis)

  4. LockSupport.parkNanos

  5. LockSupport.parkUntil

Para ler mais sobre as diferenças entrewait()esleep() em Java, dê uma olhada emthis dedicated article here.

Por enquanto, vamos tentar reproduzir rapidamente este estado:

public class TimedWaitingState {
    public static void main(String[] args) throws InterruptedException {
        DemoThread obj1 = new DemoThread();
        Thread t1 = new Thread(obj1);
        t1.start();

        // The following sleep will give enough time for ThreadScheduler
        // to start processing of thread t1
        Thread.sleep(1000);
        Log.info(t1.getState());
    }
}

class DemoThread implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }
    }
}

Aqui, criamos e iniciamos um threadt1 que entrou no estado de hibernação com um período de tempo limite de 5 segundos; a saída será:

TIMED_WAITING

3.6. Terminado

Este é o estado de um encadeamento morto. It’s in the TERMINATED state when it has either finished execution or was terminated abnormally.

Temosa dedicated article que discute diferentes maneiras de interromper o thread.

Vamos tentar atingir esse estado no exemplo a seguir:

public class TerminatedState implements Runnable {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new TerminatedState());
        t1.start();
        // The following sleep method will give enough time for
        // thread t1 to complete
        Thread.sleep(1000);
        Log.info(t1.getState());
    }

    @Override
    public void run() {
        // No processing in this block
    }
}

Aqui, enquanto iniciamos o encadeamentot1, a próxima instruçãoThread.sleep(1000) dá tempo suficiente parat1 ser concluído e, portanto, este programa nos dá a saída como:

TERMINATED

4. Conclusão

Neste tutorial, aprendemos sobre o ciclo de vida de um encadeamento em Java. Vimos todos os seis estados definidos porThread.State enum e os reproduzimos com exemplos rápidos.

Embora os trechos de código tenham a mesma saída em quase todas as máquinas, em alguns casos excepcionais, podemos obter algumas saídas diferentes, pois o comportamento exato do Thread Scheduler não pode ser determinado.

E, como sempre, os fragmentos de código usados ​​aqui sãoavailable on GitHub.