Simultaneidade Java - Visão geral

Java é uma linguagem de programação multithread, o que significa que podemos desenvolver programas multithread usando Java. Um programa multi-threaded contém duas ou mais partes que podem ser executadas simultaneamente e cada parte pode lidar com uma tarefa diferente ao mesmo tempo, fazendo uso otimizado dos recursos disponíveis, especialmente quando seu computador tem várias CPUs.

Por definição, multitarefa é quando vários processos compartilham recursos de processamento comuns, como uma CPU. O multi-threading estende a ideia de multitarefa em aplicativos onde você pode subdividir operações específicas em um único aplicativo em threads individuais. Cada um dos threads pode ser executado em paralelo. O sistema operacional divide o tempo de processamento não apenas entre os diferentes aplicativos, mas também entre cada thread de um aplicativo.

Multi-threading permite que você escreva de uma maneira em que várias atividades possam prosseguir simultaneamente no mesmo programa.

Ciclo de Vida de um Tópico

Um segmento passa por vários estágios de seu ciclo de vida. Por exemplo, um thread nasce, é iniciado, é executado e, em seguida, morre. O diagrama a seguir mostra o ciclo de vida completo de um encadeamento.

A seguir estão as etapas do ciclo de vida -

  • New- Um novo encadeamento inicia seu ciclo de vida no novo estado. Ele permanece neste estado até que o programa inicie o thread. Também é conhecido comoborn thread.

  • Runnable- Depois que um encadeamento recém-nascido é iniciado, o encadeamento se torna executável. Um thread neste estado é considerado como executando sua tarefa.

  • Waiting- Às vezes, um thread faz a transição para o estado de espera enquanto espera por outro thread para realizar uma tarefa. Um thread faz a transição de volta ao estado executável apenas quando outro thread sinaliza ao thread em espera para continuar em execução.

  • Timed Waiting- Um thread executável pode entrar no estado de espera cronometrado por um intervalo de tempo especificado. Um encadeamento nesse estado faz a transição de volta ao estado executável quando esse intervalo de tempo expira ou quando o evento pelo qual está esperando ocorre.

  • Terminated (Dead) - Um thread executável entra no estado finalizado quando ele conclui sua tarefa ou então termina.

Prioridades de discussão

Cada encadeamento Java tem uma prioridade que ajuda o sistema operacional a determinar a ordem em que os encadeamentos são planejados.

As prioridades de encadeamento Java estão no intervalo entre MIN_PRIORITY (uma constante de 1) e MAX_PRIORITY (uma constante de 10). Por padrão, cada thread tem prioridade NORM_PRIORITY (uma constante de 5).

Threads com prioridade mais alta são mais importantes para um programa e devem ter tempo de processador alocado antes de threads de prioridade mais baixa. No entanto, as prioridades de thread não podem garantir a ordem em que os threads são executados e são muito dependentes da plataforma.

Crie um thread implementando uma interface executável

Se sua classe se destina a ser executada como um thread, você pode conseguir isso implementando um Runnableinterface. Você precisará seguir três etapas básicas -

Passo 1

Como primeira etapa, você precisa implementar um método run () fornecido por um Runnableinterface. Este método fornece um ponto de entrada para o encadeamento e você colocará sua lógica de negócios completa dentro desse método. A seguir está uma sintaxe simples do método run () -

public void run( )

Passo 2

Como uma segunda etapa, você instanciará um Thread objeto usando o seguinte construtor -

Thread(Runnable threadObj, String threadName);

Onde, threadObj é uma instância de uma classe que implementa oRunnable interface e threadName é o nome dado ao novo tópico.

etapa 3

Depois que um objeto Thread é criado, você pode iniciá-lo chamando start(), que executa uma chamada ao método run (). A seguir está uma sintaxe simples do método start () -

void start();

Example

Aqui está um exemplo que cria um novo thread e começa a executá-lo -

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;

   RunnableDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      
      try {
      
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo("Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo("Thread-2");
      R2.start();
   }   
}

Isso produzirá o seguinte resultado -

Output

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Criar um thread estendendo uma classe de thread

A segunda maneira de criar um thread é criar uma nova classe que estende Threadclasse usando as duas etapas simples a seguir. Esta abordagem fornece mais flexibilidade no tratamento de vários threads criados usando os métodos disponíveis na classe Thread.

Passo 1

Você precisará substituir run( )método disponível na classe Thread. Este método fornece um ponto de entrada para o encadeamento e você colocará sua lógica de negócios completa dentro desse método. A seguir está uma sintaxe simples do método run () -

public void run( )

Passo 2

Uma vez que o objeto Thread é criado, você pode iniciá-lo chamando start(), que executa uma chamada ao método run (). A seguir está uma sintaxe simples do método start () -

void start( );

Example

Aqui está o programa anterior reescrito para estender o Thread -

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      
      try {

         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo("Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo("Thread-2");
      T2.start();
   }   
}

Isso produzirá o seguinte resultado -

Output

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.