Java e Threads
Threads são essencialmente subprocessos. Informalmente, você pode considerá-las como tarefas (tasks) que pertencem a um programa e que podem ser executadas “simultaneamente”. Dependendo do número de CPUs disponíveis e do número de threads concorrentes, algumas threads realmente serão executadas em processadores diferentes, enquanto em outros casos, a ilusão de uma execução simultânea será atingida pelo “malabarismo” de threads dentro e fora das CPUs. Uma parte do sistema operacional chamado thread scheduler se encarrega de decidir quais thread podem alocar tempo de CPU (em qual CPUs) e quando.
Introdução: O que são threads e como usá-las em Java
É mais fácil para ilustrar o que é uma thread vendo alguns códigos. Vamos escrever um programa que “divide-se” em duas threads simultâneas. Uma thread irá imprimir “Olá, mundo!” a cada segundo. A outra irá imprimir “Adeus, mundo cruel!” a cada dois segundos. Ok é um exemplo bobo.
Para eles serem executados simultaneamente, cada uma dessas tarefas será executada em uma thread separada. Para definir uma tarefa, criamos uma instância do Runnable. Então, vamos atribuir cada um desses Runnable a um objeto Thread.
Runnable
Um objeto Runnable define uma tarefa que será executada. Ele não define como deve ser executada (em série, duas vezes, três em um tempo, etc), mas apenas o que. Podemos definir um Runnable da seguinte maneira:
Runnable r = new Runnable() {
public void run() {
//... código a ser executado ...
}
};
O Runnable na verdade é uma interface, com um único método run(). No nosso caso, queremos que o Runnable.run(), das nossas duas tarefas, imprimem uma mensagem periodicamente. Então o código que poderia ser assim:
Runnable r1 = new Runnable() {
public void run() {
try {
while (true) {
System.out.println("Olá, mundo!");
Thread.sleep(1000L);
}
} catch (InterruptedException iex) {}
}
};
Runnable r2 = new Runnable() {
public void run() {
try {
while (true) {
System.out.println("Adeus, " + "mundo cruel!");
Thread.sleep(2000L);
}
} catch (InterruptedException iex) {}
}
};
Por enquanto não vamos entrar em alguns detalhes, como o fato da tarefa nunca parar, já que se trata de um laço infinito. O ponto mais importante é que com a interface Runnable(), estamos apenas definindo o que são as duas tarefas. Nós não definimos como elas irão ser executadas, e é nesta parte que entra a thread.
Thread
Um objeto Thread efetivamente define como a tarefa deve ser executada, ou seja, ao mesmo tempo, sequenciais. Para executar duas tarefas simultaneamente, é necessário criar duas threads, por isto criamos dois Runnable, uma para cada thread, e depois chamar o método start() para cada thread:
Thread thr1 = new Thread(r1);
Thread thr2 = new Thread(r2);
thr1.start();
thr2.start();
Quando chamamos o método start(), uma nova thread é gerada, assim em algum momento do instante seguinte a tarefa começará a ser executada. Enquanto isto, o controle retorna para a chamada de start(), e podemos iniciar a segunda thread. Assim teremos três threads executando em paralelo, as duas que acabamos de criar e a thread principal do programa (Na verdade o JVM cria alguma thread para a execução de algumas tarefas, como o Garbarge Colletion, embora estejam essencialmente fora do controle do nosso programa).
