Threads em Java
Autor: Leandro Siciliano | Publicado: 2012-04-10T18:42:00-07:00

O que é uma thread ?

Thread pode ser definida como um fluxo sequencial de execução de um programa. Logo, um programa pode ser dividido em partes sequênciais não concorrentes de sua execução em threads distintas, conferindo paralelismo na execução destas.

Thread em Java

A máquina virtual Java permite que uma aplicação tenha diversos fluxos rodando concorrentemente. Para isso a API Java disponibiliza a classe Thread e a interface Runnable.



Classe Thread


Uma classe pode estender da classe pai chamada "Thread". Essa implementação exige a implementação do método run(), que contém o código a ser executado pela thread em si.



Ex:


public class ExemploThread extends Thread {

&nbsp; &nbsp; &nbsp;public void run() {

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int total = 0;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while ((int)(Math.random()*100) != 50)

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; total++;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Sou a " + this.getName() + " e tentei " + total + " vezes.");

&nbsp; &nbsp; &nbsp;}




Para rodar a thread é só instanciar o objeto e chamar o método start():



ExemploThread t = new ExemploThread();

t.start();



Esse por sinal é responsável em chamar o método run.




Interface Runnable


A linguagem Java não permite herança múltipla, logo, foi criada pela Sun uma alternativa para o uso de mais uma superclasse, que é a utilização de interfaces. Essa interface tem um funcionamento bem parecido com a classe Thread, ao exigir a implementação do método Run().&nbsp;Diferente de implementações que utilizam a classe Thread diretamente, as que utilizam a interface&nbsp;Runnable possuem algumas particularidades. Após instanciar o objeto que possui a interface Runnable, é&nbsp;necessário instanciar também um objeto da classe Thread que receba em seu método construtor uma&nbsp;referência ao objeto da interface Runnable, bem como um nome para a thread criada. Após instanciar este&nbsp;objeto da classe Thread, pode-se iniciar a &nbsp;thread a partir do seu método start().&nbsp;




Ex:

public class ExemploRunnable implements Runnable {

&nbsp; &nbsp; &nbsp;public void run() {

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int total = 0;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while ((int)(Math.random()*100) != 50)

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; total++;

&nbsp; &nbsp; &nbsp;}

}



public class Main {

&nbsp; &nbsp; &nbsp;public static void main(String[] args) {

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ExemploRunnable r = new ExemploRunnable();

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Thread t = new Thread(r, "Thread 1");

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;t.start();

&nbsp; &nbsp; &nbsp;}



}




Esta interface torna-se muito importante, pois em diversos momentos é necessário que uma classe&nbsp;

tenha dois pais ao mesmo tempo. Um bom exemplo deste tipo de aplicação é para interfaces gráficas. Uma&nbsp;

classe criada para fazer &nbsp;uma janela, por exemplo, pode ser filha da classe JPanel e, para possibilitar&nbsp;

paralelismo e uma melhor experiência para o usuário, pode implementar a classe Runnable.




Ciclo de vida de uma Thread








Uma &nbsp;thread, do momento em que é criada até o qual é finalizada, passa por diversos estados e&nbsp;

transições.



Como mencionado anteriormente, as threads são criadas a partir de sua instanciação. Ao disparar o&nbsp;

método start(), ela será colocada na lista de threads prontas a serem executadas pelo sistema operacional.&nbsp;

Quando o sistema operacional seleciona uma thread para ser executada, ela permanece no estado Execução,&nbsp;produzindo as ações do método run().Uma thread permanece em Execução até que: seu tempo de uso da CPU se&nbsp;esgote ou com a chamada do método yield() quando executa um sleep(), permanecendo no estado Suspenso&nbsp;durante o tempo estabelecido e voltando ao estado &nbsp;Pronto, em seguida; quando executa um wait(),&nbsp;permanecendo no estado Suspenso até que outra thread execute um notify() ou notifyAll(), voltando ao&nbsp;estado Pronto em seguida; quando necessita de uma operação de I/O, ficando no estado Bloqueado até que a&nbsp;operação seja concluída, voltado ao estado Pronto; se a thread finalizar a execução do seu método run() ou&nbsp;quando for executado o método interrupt(), indo para o estado Finalizado




Prioridades




A prioridade de uma thread corresponde a preferência que ela terá perante as demais durante sua&nbsp;

execução. Quanto maior a prioridade de uma thread, maior será sua preferência no uso da CPU. Threads de&nbsp;mesma prioridade costumam partilhar o tempo de CPU igualmente.

A prioridade é extremamente ligada ao algoritmo de escalonamento de CPU que o sistema&nbsp;

operacional utiliza. Para definir a prioridade de uma thread, são usados números de 1 a 10, sendo que o&nbsp;

número 5 é usado para definir a prioridade como normal. Entretanto, nem todos os sistemas operacionais&nbsp;

possuem as mesmas prioridades de uma thread Java. Portanto, para garantir que uma thread com prioridade&nbsp;10 tenha prioridade alta tanto em um sistema operacional cuja prioridade máxima seja 10 quanto em outro&nbsp;que seja 100, a JVM traduz a prioridade especificada no código para a do sistema operacional, logo uma&nbsp;prioridade 10 em Java pode ser traduzida para uma prioridade 100, por exemplo.





Sincronização



Durante a execução de threads, há casos em que elas trabalham independentemente uma da outra,&nbsp;

sem necessidade de qualquer comunicação entre elas e há casos em que elas comunicam-se de alguma forma&nbsp;ou utilizam dados em comum, denominadas assíncronas e síncronas, respectivamente.

Em threads síncronas, geralmente é necessário que a informação que está sendo compartilhada seja&nbsp;

consistente, evitando que duas threads mexam nesta ao mesmo tempo, gerando um resultado inconsistente.&nbsp;

Para tanto, na linguagem Java há um mecanismo de sincronização, onde esta consistência pode ser garantida.

Tal mecanismo pode ser utilizado com a palavra reservada synchronized, aplicada a um método, a um bloco&nbsp;

ou mesmo a uma diretiva isolada.

Os métodos wait(), notify() e notifyAll() também são muito importantes na sincronização, sendo&nbsp;

responsáveis por provocar,&nbsp;respectivamente: uma espera, a liberação de uma ou mais &nbsp;threads em espera.




Resumo de métodos das threads


Run(): Deve estar presente em todas as threads
Start(): Registra a thread no thread scheduler, ou seja, a coloca na fila de execução
getName()/setName(): Atribui e retorna o nome de uma thread. Por default thread são nomeadas por números.
Yield(): Faz com que a thread corrente pare para que outra possa ser executada.
Sleep(): Faz com que a thread fique parada por um tempo (em milesegundos) para que a CPU execute outras threads.
Interrupt(): Atribui a thread o estado de que não pode ser interrompida.
isInterrupted(): Verifica que a thread está no estado "interrupt"
getPriority()/setPriority(): atribui e retorna o estado de prioridade de uma thread
Join(): condiciona a continuação de uma thread a finalização de outra.