Escolar Documentos
Profissional Documentos
Cultura Documentos
1) Introdução
As aplicações desenvolvidas com Java são executadas por meio de threads, que são caminhos
diferentes de execução do código do programa. Quando várias threads estão executando, o
caminho de uma thread pode ser diferente do caminho de outra thread.
Vamos considerar, por exemplo, a estrutura switch/case, sendo que threads diferentes
podem lidar com cada um dos cases.
Toda aplicação Java tem uma thread padrão que executa o método main(). A aplicação
também pode criar threads que lidam com tarefas que demandem maior poderio
computacional (como recursos de processamento e memória) executando em segundo plano,
de modo que seja possível outros processamentos possam ser realizados como, por exemplo,
responder aos acionamentos do mouse, do teclado, etc. Essas threads executam sequências de
códigos encapsuladas em objetos que são denominados runnables.
A JVM fornece a cada thread sua própria pilha JVM para evitar que haja interferências
entre threads diferentes. Esta abordagem de pilhas separadas permite que as threads
acompanhem a próxima instrução a ser executada, que pode diferir de uma para outra thread.
É possível lidar com threads em Java de duas formas diferentes:
• Classe java.lang.Thread;
• Interface java.lang.Runnable.
2) Ciclo de vida de uma thread
Uma trhead passa por diferentes estágios durante a sua existência. Usaremos os termos
em Inglês objetivando facilitar o entendimento das funções que serão estudadas
posteriormente. A Figura 1 ilustra o ciclo de vida das threads.
• New: uma nova thread é gerada e começa o seu ciclo de vida. Ela permanece neste
estágio até que o programa inicie-a pelo método start();
• Runnable: depois que uma thread foi criada e inicializada, ela é considerada executável
(Runnable);
• Running: depois que uma thread entra no estado executável, é possível utilizar o
método run() para, de fato, executá-la, de modo que ela realize o processamento que
foi designada a fazer;
• Waiting: objetivando a sincronização dos processamentos das threads,
frequentemente, é necessário utilizar recursos que possam atrasar a continuidade do
processamento das threads, de modo que elas possam esperar que outras threads
realizem seus processamentos antes que ela continue o seu. Por meio dos métodos
sleep() e wait(), podemos estabelecer a sincronização.
• Dead: quando a thread é finalizada.
Cada thread em Java tem uma prioridade que ajuda o Sistema Operacional a determinar
a ordem na qual as threads serão executadas.
Threads com altas prioridades são mais importantes para um programa e devem ser
alocados tempos de processamento para que elas sejam executadas antes das threads com
menores níveis de prioridades. Entretanto, é importante atentar para qualquer alteração que se
considere fazer nos níveis de prioridade porque eventuais erros podem comprometer o
processamento.
4) Utilização de threads por meio da interface Runnable
Se uma determinada classe precisa ser executada como uma thread, então podemos
implementar por meio da interface Runnable.
Sendo que threadObj é a instância de uma classe que implementa a interface Runnable.
E threadName é o nome dado para a nova thread.
Uma vez que o objeto Thread é criado, pode-se inicializa-lo por meio da invocação do
método start() que, por sua vez, executa a chamada para o método run().
Vamos ver agora um exemplo completo, que utiliza as funções descritas acima.
A saída do programa será:
5) Utilização de threads por meio da classe Thread
Ainda de forma semelhante ao caso anterior, uma vez que um objeto Thread é
instanciado, ele é iniciado por meio do método start(), que chama o método run().
A interface Runnable tem o código necessário para ser executados pela thread que está
associada com um objeto Thread. Este código está localizado no método run() de Runnable.
Com exceção da thread associada ao método main(), as threads são introduzidas por
meio dos objetos Thread e Runnable. Thread declara vários construtores para a inicialização de
objetos Thread. E vários destes construtores requerem um objeto Runnable como argumento.
Ants do Java 8, esta era a única maneira de criar um runnable. Porém, Java 8 introduziu
a denominada expressão lambda, que permite que se crie runnable de forma mais simplificada,
conforme mostrado a seguir:
Depois da criação do objeto Runnable (r), pode-se passa-lo como parâmetro de entrada
do construtor Thread que recebe um argumento do tipo Runnale, conforme mostrado no
fragmento de código abaixo:
O código acima criou então um objeto t, que é do tipo Thread, a partir de um objeto r,
do tipo Runnable.
Mas alguns construtores podem não utilizar argumentos do tipo Runnable e, nestes
casos, é necessário sobrescrever seu método run() para possibilitar a execução do código,
conforme mostra o fragmento de código abaixo: