Threads são linhas de execução concorrente, alguns autores chamam Threads de processos, mas em Java uma Thread não é um processo pois ela não recebe um process ID do sistema operacional.
Basicamente são códigos distintos que executam "ao mesmo tempo", na verdade essas linhas não são executadas ao mesmo tempo, elas são executadas de forma concorrente, isso significa que elas disputam "fatias de tempo" do processador, dessa forma cada uma executa um pouquinho de código de cada vez.
Como a troca de contextos do processador acontece de forma muito rápida, a percepção que temos é de que os códigos são executados ao mesmo tempo, ou paralelamente, mas vale lembrar que na verdade eles executam concorrentemente.
Para criar e executar uma Thread em Java, basta fazer o seguinte:
-
implementar a interface Runnable. Alguns autores extendem a classe Thread, no entanto esta prática não é recomendada já que arquiteturalmente falando, você só deveria extender uma classe caso precise modificar o comportamento dela;
-
no método run da interface Runnable, implementar ou invocar o código que deve ser executado concorrentemente;
-
instanciar a classe Thread, passando como parâmetro um objeto que implemente a interface Runnable;
-
invocar o método start do objeto Thread instanciado.
Abaixo tempos um exemplo prático, compile e execute o código e veja o que acontece:
/**
* Exemplo de execução concorrente em Java
*
* @author Ricardo Artur Staroski
*/
public class Exemplo {
// essa linha de execução só vai imprimir os números de 0 a 10
class ImpressorDeNumeros implements Runnable {
// esse é o método que será executado concorrentemente
@Override
public void run() {
imprimeNumeros();
}
}
// essa linha de execução vai imprimir as letras de 'a' a 'z'
class ImpressorDeLetras implements Runnable {
// esse é o método que será executado concorrentemente
public void run() {
imprimeLetras();
}
}
/**
* esse é o método principal, o ponto de entrada do nosso exemplo
*/
public static void main(String[] args) {
// vamos instanciar esta classe
Exemplo exemplo = new Exemplo();
// e agora vamos executá-la
exemplo.executa();
}
// método que executa nosso exemplo
private void executa() {
// criar os objetos Runnable
Runnable concorrente1 = new ImpressorDeLetras();
Runnable concorrente2 = new ImpressorDeNumeros();
// criar as linhas de execução concorrente para os objetos
Thread linhaExecucao1 = new Thread(concorrente1);
Thread linhaExecucao2 = new Thread(concorrente2);
// disparar as linhas de execução
linhaExecucao1.start();
linhaExecucao2.start();
// as outras duas linhas de execução já estão em andamento "ao mesmo tempo"
// agora vamos imprimri qualquer coisa "ao mesmo tempo" que elas
imprimeQualquerCoisa();
}
// método que imprime os números de 0 à 9
private void imprimeNumeros() {
for (int numero = 0; numero <= 9; numero++) {
System.out.println("imprimindo numero " + numero);
esperaUmPouquinho();
}
}
// método que imprime as letras de 'a' à 'z'
private void imprimeLetras() {
for (char letra = 'a'; letra <= 'z'; letra++) {
System.out.println("imprimindo letra " + letra);
esperaUmPouquinho();
}
}
// método que imprime qualquer coisa
private void imprimeQualquerCoisa() {
for (int i = 1; i <= 50; i++) {
System.out.println("imprimindo qualquer coisa " + i);
esperaUmPouquinho();
}
}
// método espera meio segundo antes de continuar
private void esperaUmPouquinho() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}