1. Passagem de parâmetros para threads
Quando você inicia uma thread, muitas vezes quer passar a ela algum “trabalho”: nome de arquivo, intervalo de números ou uma saudação. Uma thread sem parâmetros — é como um entregador sem endereço: corre pela cidade, mas não sabe para onde entregar a pizza.
Como fazer isso?
Em Java, as threads geralmente são criadas de duas formas:
- Herdando da classe Thread
- Implementando a interface Runnable (ou usando uma expressão lambda)
A passagem de parâmetros é feita, na maioria das vezes, pelo construtor da classe que implementa Runnable. É simples, seguro e claro. Torne os campos final — e você protegerá os parâmetros contra alterações vindas de outras threads. Usar setters/campos públicos é arriscado por causa de problemas de sincronização.
Exemplo 1: Thread com parâmetro via construtor
Vamos aprimorar um aplicativo didático: processar pedidos de usuários em uma thread separada.
public class OrderProcessor implements Runnable {
private final String orderId;
public OrderProcessor(String orderId) {
this.orderId = orderId;
}
@Override
public void run() {
System.out.println("Processando pedido: " + orderId + " na thread " + Thread.currentThread().getName());
// Aqui pode haver um processamento demorado...
}
}
Criando e iniciando threads:
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(new OrderProcessor("ORDER-001"));
Thread thread2 = new Thread(new OrderProcessor("ORDER-002"));
thread1.start();
thread2.start();
}
}
Saída esperada:
Processando pedido: ORDER-001 na thread Thread-0
Processando pedido: ORDER-002 na thread Thread-1
Exemplo 2: Thread com parâmetro via expressão lambda (Java 8+)
Se a tarefa for simples, dá para dispensar uma classe separada.
public class Main {
public static void main(String[] args) {
String user1 = "Vasya";
String user2 = "Katya";
Thread thread1 = new Thread(() -> {
System.out.println("Olá, " + user1 + " de " + Thread.currentThread().getName());
});
Thread thread2 = new Thread(() -> {
System.out.println("Olá, " + user2 + " de " + Thread.currentThread().getName());
});
thread1.start();
thread2.start();
}
}
Por que não usar setters/getters para passar parâmetros?
Se você passa parâmetros por setters ou campos públicos, há o risco de outra thread alterar o valor durante a execução. Isso pode levar a erros difíceis de detectar. É melhor tornar os campos final e passá-los pelo construtor.
2. Prioridades de threads
Em Java, cada thread tem uma prioridade — um número inteiro de 1 a 10, que informa ao escalonador (scheduler) quão “importante” é essa thread em comparação com as outras. Por padrão, todas as threads têm prioridade 5 (Thread.NORM_PRIORITY).
Importante: a prioridade é apenas uma “dica” para o SO. Não é garantia de que uma thread com prioridade 10 rodará mais rápido que uma com prioridade 1. Tudo depende do SO, de suas configurações e da carga atual.
Como definir a prioridade de uma thread?
A classe Thread possui os métodos:
- setPriority(int newPriority)
- getPriority()
E três constantes padrão:
- Thread.MIN_PRIORITY (1)
- Thread.NORM_PRIORITY (5)
- Thread.MAX_PRIORITY (10)
Exemplo 3: Definindo a prioridade de uma thread
public class PriorityDemo {
public static void main(String[] args) {
Runnable task = () -> {
System.out.println("Thread " + Thread.currentThread().getName() +
" com prioridade " + Thread.currentThread().getPriority());
};
Thread low = new Thread(task, "LowPriority");
Thread norm = new Thread(task, "NormalPriority");
Thread high = new Thread(task, "HighPriority");
low.setPriority(Thread.MIN_PRIORITY); // 1
norm.setPriority(Thread.NORM_PRIORITY); // 5
high.setPriority(Thread.MAX_PRIORITY); // 10
low.start();
norm.start();
high.start();
}
}
Saída esperada (a ordem das linhas não é garantida!):
Thread LowPriority com prioridade 1
Thread HighPriority com prioridade 10
Thread NormalPriority com prioridade 5
A prioridade influencia a ordem de execução?
Na maioria dos casos — não. As prioridades podem influenciar quanto tempo de CPU a thread recebe, mas não garantem a ordem de início ou término. Não baseie a lógica do programa em prioridades — use-as como “dicas” suaves, por exemplo, para que uma thread em segundo plano não atrapalhe a principal.
Tabela: Constantes de prioridade de threads
| Constante | Valor | Descrição |
|---|---|---|
|
1 | Prioridade mais baixa |
|
5 | Prioridade normal |
|
10 | Prioridade mais alta |
3. Nomeando threads
O nome da thread é um “apelido” no mundo da multitarefa. Quando você tem dezenas de threads, é mais fácil depurar se, em vez de "Thread-7", você vir "FileUploader-1" no log. Isso é especialmente importante ao analisar logs e buscar erros.
Como definir o nome de uma thread?
O nome pode ser informado diretamente no construtor de Thread ou definido com o método setName. Para obter o nome atual — getName.
Thread t = new Thread(() -> {
System.out.println("Estou trabalhando!");
}, "MyThreadName");
t.start();
Exemplo 4: Threads nomeadas
public class NamedThreads {
public static void main(String[] args) {
Thread threadA = new Thread(() -> {
System.out.println("Sou a thread: " + Thread.currentThread().getName());
}, "Downloader");
Thread threadB = new Thread(() -> {
System.out.println("Sou a thread: " + Thread.currentThread().getName());
});
threadB.setName("Uploader");
threadA.start();
threadB.start();
}
}
Saída esperada:
Sou a thread: Downloader
Sou a thread: Uploader
4. Prática: várias threads com parâmetros, prioridades e nomes diferentes
Vamos juntar tudo em um único exemplo: cada pedido — uma thread separada com seu próprio nome e prioridade.
public class OrderProcessor implements Runnable {
private final String orderId;
private final int processingTimeMs;
public OrderProcessor(String orderId, int processingTimeMs) {
this.orderId = orderId;
this.processingTimeMs = processingTimeMs;
}
@Override
public void run() {
System.out.println("[" + Thread.currentThread().getName() + "] Iniciei o processamento do pedido " + orderId +
" (prioridade " + Thread.currentThread().getPriority() + ")");
try {
Thread.sleep(processingTimeMs); // simulação de trabalho
} catch (InterruptedException e) {
System.out.println("[" + Thread.currentThread().getName() + "] Interrompido!");
}
System.out.println("[" + Thread.currentThread().getName() + "] Concluí o processamento do pedido " + orderId);
}
public static void main(String[] args) {
Thread fastOrder = new Thread(new OrderProcessor("FAST-ORDER", 500), "FastOrderThread");
Thread normalOrder = new Thread(new OrderProcessor("NORMAL-ORDER", 1000), "NormalOrderThread");
Thread slowOrder = new Thread(new OrderProcessor("SLOW-ORDER", 2000), "SlowOrderThread");
fastOrder.setPriority(Thread.MAX_PRIORITY);
normalOrder.setPriority(Thread.NORM_PRIORITY);
slowOrder.setPriority(Thread.MIN_PRIORITY);
fastOrder.start();
normalOrder.start();
slowOrder.start();
}
}
O que veremos:
- Cada thread informa qual pedido está processando, seu nome e sua prioridade.
- O tempo de processamento é simulado com Thread.sleep.
- A ordem de conclusão das threads pode não corresponder à prioridade.
5. Pontos importantes e particularidades
Passagem de parâmetros: apenas via construtor!
É mais seguro. Declare os parâmetros como final — eles não poderão ser alterados após a criação do objeto, e nenhuma outra thread vai “injetar” seus próprios valores. Isso é crucial para prevenir condições de corrida.
Prioridades: não baseie nelas a lógica de negócio
Prioridades são como pedir ao garçom: “Pode trazer o café mais rápido?”. Às vezes funciona, às vezes — não. É uma recomendação para o SO, não uma regra de execução.
Nomes de threads: use para depuração
Economiza muito tempo ao analisar logs. Acostume-se a definir nomes significativos desde o início.
6. Erros típicos ao trabalhar com parâmetros e prioridades de threads
Erro nº 1: passar parâmetros por campos públicos. Se você declara os parâmetros como campos comuns e os altera após o início da thread, pode obter resultados imprevisíveis. Use campos final e o construtor.
Erro nº 2: esperar que a prioridade garanta a ordem. Você definiu Thread.MAX_PRIORITY — e acha que a thread será sempre a primeira? Não. Não use prioridades para sincronização ou controle da lógica.
Erro nº 3: threads sem nome nos logs. Quando no log há apenas “Thread-3”, “Thread-7”, é difícil achar o responsável. Dê nomes significativos às threads usando o construtor ou setName.
Erro nº 4: usar o mesmo objeto Runnable para várias threads. Se o objeto Runnable mantém estado e você o passa para várias threads, elas “compartilham” os parâmetros — caminho direto para condições de corrida. Crie um Runnable separado por thread.
Erro nº 5: passar parâmetros por métodos set. Se você define parâmetros por set*-métodos já depois da criação/início da thread, os valores podem mudar “em voo” — a clássica race condition.
GO TO FULL VERSION