Atualizado: 26/07/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Criação e Execução de Threads em Java

Para criar uma nova thread, existem duas abordagens principais em Java: estender a classe Thread ou implementar a interface Runnable.

Abordagem 1: Herança da Classe Thread

A primeira abordagem consiste em criar uma classe que herda diretamente de Thread e sobrescreve seu método run().

class JThread extends Thread {

    JThread(String name) {
        super(name);
    }

    public void run() {
        System.out.printf("%s started... \n", Thread.currentThread().getName());

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            System.out.println("Thread has been interrupted");
        }
        System.out.printf("%s finished... \n", Thread.currentThread().getName());
    }
}

public class Program {

    public static void main(String[] args) {
        System.out.println("Main thread started...");
        new JThread("JThread").start();
        System.out.println("Main thread finished...");
    }
}

Neste exemplo, a classe JThread é uma thread. Seu construtor recebe um nome e o repassa para o construtor da superclasse (Thread). A lógica a ser executada na nova linha de execução é definida dentro do método run().

No método main, a chamada de start() em uma instância de JThread instrui a JVM a iniciar uma nova thread. Em seguida, a JVM chama o método run() dessa thread.

Saída no console:

Main thread started...
Main thread finished...
JThread started...
JThread finished...

Observe que a thread principal (main) termina sua execução antes da JThread, demonstrando que elas operam de forma independente.

Da mesma forma, é possível iniciar múltiplas threads:

public static void main(String[] args) {
    System.out.println("Main thread started...");
    for (int i = 1; i < 6; i++) {
        new JThread("JThread " + i).start();
    }
    System.out.println("Main thread finished...");
}

Saída no console (exemplo):

Main thread started...
Main thread finished...
JThread 2 started...
JThread 5 started...
JThread 4 started...
JThread 1 started...
JThread 3 started...
JThread 1 finished...
JThread 2 finished...
JThread 5 finished...
JThread 4 finished...
JThread 3 finished...

A ordem de início e término das threads não é garantida, pois depende do escalonador de threads do sistema operacional.

Aguardando a Finalização de uma Thread

Em muitos cenários, é necessário que a thread principal espere a conclusão de outras. Para isso, utiliza-se o método join(). A thread que chama join() em outra ficará em estado de espera até que a segunda termine.

public static void main(String[] args) {
    System.out.println("Main thread started...");
    JThread t = new JThread("JThread");
    t.start();

    try {
        t.join(); // A thread main aguarda a finalização da thread t
    } catch (InterruptedException e) {
        System.out.printf("%s has been interrupted", t.getName());
    }
    System.out.println("Main thread finished...");
}

Neste caso, a main thread só executará a última linha de código após a finalização completa da thread t.

Saída no console:

Main thread started...
JThread started...
JThread finished...
Main thread finished...

Abordagem 2: Implementação da Interface Runnable

Esta é a abordagem mais recomendada e flexível. Em vez de herdar de Thread, a classe implementa a interface Runnable.

Esta prática é preferível por duas razões principais:

  1. Java não suporta herança múltipla. Se uma classe já precisa herdar de outra, ela não poderá herdar também de Thread.
  2. Promove um design de código mais limpo, pois separa a tarefa (o que deve ser feito, definido no Runnable) do mecanismo de execução (o objeto Thread que executa a tarefa).

A interface Runnable define um único método: run().

class MyTask implements Runnable {

    public void run() {
        System.out.printf("%s started... \n", Thread.currentThread().getName());

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            System.out.println("Thread has been interrupted");
        }
        System.out.printf("%s finished... \n", Thread.currentThread().getName());
    }
}

public class Program {

    public static void main(String[] args) {
        System.out.println("Main thread started...");
        Runnable task = new MyTask();
        Thread myThread = new Thread(task, "MyThread");
        myThread.start();
        System.out.println("Main thread finished...");
    }
}

A lógica de execução é a mesma, mas a criação é diferente. Primeiro, cria-se uma instância da tarefa (MyTask). Em seguida, esse objeto é passado para o construtor da classe Thread. É o objeto Thread que gerencia a execução.

Saída no console:

Main thread started...
Main thread finished...
MyThread started...
MyThread finished...

Como Runnable é uma interface funcional, sua implementação pode ser simplificada com uma expressão lambda, eliminando a necessidade de uma classe separada para tarefas simples.

public class Program {

    public static void main(String[] args) {
        System.out.println("Main thread started...");

        Runnable task = () -> {
            System.out.printf("%s started... \n", Thread.currentThread().getName());

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                System.out.println("Thread has been interrupted");
            }
            System.out.printf("%s finished... \n", Thread.currentThread().getName());
        };

        Thread myThread = new Thread(task, "MyThread");
        myThread.start();

        System.out.println("Main thread finished...");
    }
}

Resumo

  • Existem duas formas de criar threads: herdando da classe Thread ou implementando a interface Runnable.
  • A implementação de Runnable é geralmente preferível por ser mais flexível e promover um melhor design de código.
  • O método start() inicia uma nova linha de execução, que por sua vez executa o código contido no método run().
  • O método join() é usado para fazer com que uma thread espere pela finalização de outra.
  • Expressões lambda oferecem uma forma concisa de criar implementações de Runnable.
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com