CodeGym /Blogue Java /Random-PT /Multithreading: O que os métodos da classe Thread fazem
John Squirrels
Nível 41
San Francisco

Multithreading: O que os métodos da classe Thread fazem

Publicado no grupo Random-PT
Oi! Hoje continuaremos a falar sobre multithreading. Vamos examinar a classe Thread e o que alguns de seus métodos fazem. Quando estudamos métodos de classe anteriormente, geralmente apenas escrevemos isto: <nome do método> -> <o que o método faz>. Multithreading: O que os métodos da classe Thread fazem - 1Isso não funcionará com Threados métodos de :) Eles têm uma lógica mais complexa que você não conseguirá descobrir sem alguns exemplos.

O método Thread.start()

Vamos começar nos repetindo. Como você provavelmente se lembra, você pode criar um thread fazendo sua classe herdar a Threadclasse e substituindo o run()método. Mas não vai começar sozinho, é claro. Para fazer isso, chamamos start()o método do nosso objeto. Multithreading: O que os métodos da classe Thread fazem - 2Vamos relembrar o exemplo da lição anterior:

public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Thread executed: " + getName());
   }
}


public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Observação: para iniciar um thread, você deve chamar ostart()método especial em vez dorun()método! Este é um erro fácil de cometer, especialmente quando você começa a estudar multithreading. Em nosso exemplo, se você chamar orun()método 10 vezes em vez destart(), obterá isto:

public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.run();
       }
   }
}
Veja os resultados do nosso programa: Tópico executado: Tópico-0 Tópico executado: Tópico-1 Tópico executado: Tópico-2 Tópico executado: Tópico-3 Tópico executado: Tópico-4 Tópico executado: Tópico-5 Tópico executado: Tópico-6 Thread executado: Thread-7 Thread executado: Thread-8 Thread executado: Thread-9 Observe a ordem da saída: Tudo está acontecendo em perfeita ordem. Estranho, né? Não estamos acostumados com isso, pois já sabemos que a ordem em que as threads são iniciadas e executadas é determinada por um intelecto superior dentro do nosso sistema operacional: o agendador de threads. Talvez tenhamos tido sorte? Claro, não se trata de sorte. Você pode verificar isso executando o programa mais algumas vezes. A questão é que chama orun()método diretamente não tem nada a ver com multithreading. Neste caso, o programa será executado na thread principal, a mesma thread que executa o main()método. Basta imprimir sucessivamente 10 linhas no console e pronto. 10 tópicos não foram iniciados. Portanto, lembre-se disso no futuro e verifique-se constantemente. Se você deseja que o run()método seja chamado, chame start(). Vamos mais longe.

O método Thread.sleep()

Para suspender a execução do thread atual por um tempo, usamos o sleep()método. Multithreading: O que os métodos da classe Thread fazem - 3O sleep()método leva um número de milissegundos como argumento, o que indica a quantidade de tempo para colocar o thread em hibernação.

public class Main {

   public static void main(String[] args) throws InterruptedException {

       long start = System.currentTimeMillis();

       Thread.sleep(3000);

       System.out.println(" - How long did I sleep? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " seconds");

   }
}
Saída do console: - Quanto tempo eu dormi? - 3 segundos Nota: o sleep()método é estático: ele dorme o thread atual. Ou seja, aquele que está sendo executado atualmente. Aqui está outro ponto importante: um fio adormecido pode ser interrompido. Nesse caso, o programa lança um arquivo InterruptedException. Vamos considerar um exemplo abaixo. A propósito, o que acontece depois que o thread acorda? Ele continuará a ser executado exatamente de onde parou? Não. Depois que um thread é ativado, ou seja, o tempo passado como um argumento para Thread.sleep()passou, ele faz a transição para executávelestado. Mas isso não significa que o agendador de threads irá executá-lo. Ele pode muito possivelmente dar preferência a algum outro fio não adormecido e permitir que nosso fio recém-desperto continue seu trabalho um pouco mais tarde. Lembre-se disso: acordar não significa continuar o trabalho imediatamente!

O método Thread.join()

Multithreading: O que os métodos da classe Thread fazem - 4O join()método suspende a execução do thread atual até que outro thread termine. Se temos 2 threads, t1e t2, e escrevemos

t1.join()
então t2não iniciará até que t1tenha terminado seu trabalho. O join()método pode ser usado para garantir a ordem de execução dos threads. Vamos considerar como o join()método funciona no exemplo a seguir:

public class ThreadExample extends Thread {

   @Override
   public void run() {

       System.out.println("Thread started: " + getName());

       try {
           Thread.sleep(5000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("Thread " + getName() + " is finished.");
   }
}


public class Main {

   public static void main(String[] args) throws InterruptedException {

       ThreadExample t1 = new ThreadExample();
       ThreadExample t2 = new ThreadExample();

       t1.start();


 /* The second thread (t2) will start running only after the first thread (t1)
       is finished (or an exception is thrown) */
       try {
           t1.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       t2.start();

       // The main thread will continue running only after t1 and t2 have finished
       try {
           t1.join();
           t2.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println("All threads have finished. The program is finished.");

   }
}
Criamos uma ThreadExampleclasse simples. Sua tarefa é exibir uma mensagem de que o thread foi iniciado, adormecer por 5 segundos e, finalmente, relatar que o trabalho foi concluído. Pedaco de bolo. A lógica principal está na Mainclasse. Veja os comentários: usamos o join()método para gerenciar com sucesso a ordem de execução dos threads. Se você se lembra de como começamos este tópico, a ordem de execução é tratada pelo agendador de threads. Ele executa threads a seu próprio critério: cada vez de uma maneira diferente. Aqui estamos usando o método para garantir que o t1thread será iniciado e executado primeiro, depois ot2thread, e somente depois disso o thread principal do programa continuará. Se movendo. Em programas reais, muitas vezes você encontrará situações em que precisará interromper a execução de um thread. Por exemplo, nossa thread está em execução, mas está esperando por um determinado evento ou condição. Se isso ocorrer, o encadeamento será interrompido. Provavelmente faria sentido se houvesse algum tipo de stop()método. Mas não é tão simples. Era uma vez, o Java realmente tinha um Thread.stop()método e permitia que um thread fosse interrompido. Mas foi posteriormente removido da biblioteca Java. Você pode encontrá-lo na documentação do Oracle e ver que está marcado como obsoleto. Por que? Porque simplesmente parou o thread sem fazer mais nada. Por exemplo, o encadeamento pode estar trabalhando com dados e alterando algo. Então, no meio de seu trabalho, foi cortado abruptamente e sem cerimônia pelo stop()método. Sem um desligamento adequado, nem liberação de recursos, nem mesmo tratamento de erros — não havia nada disso. Para exagerar um pouco, o stop()método simplesmente destruiu tudo em seu caminho. Foi como puxar o cabo de alimentação da tomada para desligar o computador. Sim, você pode obter o resultado desejado. Mas todo mundo sabe que depois de algumas semanas o computador não vai te agradecer por tratá-lo dessa forma. É por isso que a lógica para interromper threads mudou em Java e agora usa um interrupt()método especial.

O método Thread.interrupt()

O que acontece se o interrupt()método for chamado em um thread? Existem 2 possibilidades:
  1. Se o objeto estava no estado de espera, por exemplo, devido aos métodos joinou sleep, a espera será interrompida e o programa lançará um InterruptedException.
  2. Se o thread estiver em um estado de funcionamento, o interruptedsinalizador booleano será definido no objeto.
Mas temos que verificar o valor desse sinalizador no objeto e concluir corretamente o trabalho por conta própria! É por isso que a Threadclasse tem o boolean isInterrupted()método. Voltemos ao exemplo do relógio que estava em uma aula do curso básico. Por conveniência, simplificamos um pouco:

public class Clock extends Thread {

   public static void main(String[] args) throws InterruptedException {
       Clock clock = new Clock();
       clock.start();

       Thread.sleep(10000);
       clock.interrupt();
   }

   public void run() {
       Thread current = Thread.currentThread();

       while (!current.isInterrupted())
       {
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               System.out.println("The thread was interrupted");
               break;
           }
           System.out.println("Tick");
       }
   }
}
Neste caso, o relógio é iniciado e começa a contar a cada segundo. No décimo segundo, interrompemos o fio do relógio. Como você já sabe, se o thread que estamos tentando interromper estiver em um dos estados de espera, o resultado será um arquivo InterruptedException. Esta é uma exceção verificada, então podemos capturá-la facilmente e executar nossa lógica para terminar o programa. E foi exatamente isso que fizemos. Aqui está nosso resultado: Tick Tick Tick Tcik Tick Tick Tick Tick Tick O thread foi interrompido Isso conclui nossa introdução aos Threadmétodos mais importantes da classe. Boa sorte!
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION