Back-End

9 mai, 2008

Mais um pouco sobre threads em Java

Publicidade

Nessa nova coluna vou falar sobre “Threads”, assunto mais polêmico para quem for fazer a certificação SCJP.

Quero aproveitar e convidar aqueles que não conhecem meu blog para dar uma passada por lá. Trato de diversos assuntos relacionados à Java & T.I durante toda semana.

Claro que em uma única matéria, abordar tudo sobre thread não dá, pois o assunto leva a um livro. Mas vou buscar abordar os pontos que considero chaves.

No primeiro instante do artigo, mostrarei toda a teoria da melhor forma possível e depois algumas implementações do que abordei. No final do artigo existem uns exercícios para quem desejar treinar um pouco. Vamos lá!

É possível associar threads com muitas coisas que acontece no mundo real, mas quando vamos colocar em linguagem de programação sentimos dificuldades.

Um exemplo no mundo real:

Um caixa sendo manipulado por duas pessoas.

Aé temos duas threads com o mesmo trabalho: manipular o caixa.

Threads – não há poucas garantias.

Definição – é quando desejo que um processo rode em outra pilha, fora da thread principal main().

Métodos da class Threadstart(), sleep(), yield(), join().

  • Se não criar nenhum thread, ele está sendo executado em segundo plano.
  • Jvm´s diferentes podem executar threads de maneira distintas.
  • A ação começa no método run();

Para thread, posso dar o seguinte exemplo: desejo fazer um download de arquivos em segundo plano, enquanto estiver fazendo outra coisa no programa. Por exemplo, digitando um e-mail. Então eu quero que o trabalho seja executado no seu próprio thread, sem interferir em outras execuções.

O trabalho a começar com public void run()

Criando uma Thread.

Para criar uma instância de um Thread existem duas maneiras: estender da class Thread ou implementar a interface Runnable.

  • Usar a primeira opção é quando existe uma versão especializada da classe Thread.
  • A segunda deixa a classe livre a estender outra classe (já que se trata de uma interface).

O problema de extends é que sua classe vai ficar limitada, e de implementar é que você pode extends a outra classe qualquer e implementar.

Antes de começar a brincadeira, entenda o seguinte: toda a nova pilha em threads deve começar dentro do método public void run da interface Runnable. É nela que você vai pedir para o trabalho ser executado em segundo plano.

Extends Thread

Primeiro vamos por partes: extends a class Thread e executando uma nova tarefa.

public class Th extends Thread{//1
	public void run(){//2
		System.out.println("segundo plano");//3
	}
	public static void main(String[] args) {
		Th t = new Th();//4
			t.start();//5
			}
	/* minha class extends a Thread e executa o método run em 
	 * uma segunda pilha */}

Implements Runnable
public class Tr implements Runnable {//1
	public void run() {//2
		for(int i=0;i<3;i++)//3
			System.out.println("runnable");
	}
	public static void main(String[] args) {
		Tr t = new Tr();//4
		Thread th = new Thread(t);
			th.start();//5
	}
/* sempre tenho que ter um objeto Thread para
 * executar o meu trabalho
 */}

Desta forma temos dois threads no exemplo acima. Um é o main e o outro é o thread que criamos. Mas antes de provar isso, vou explicar o que acontece nos exemplos acima.

  1. Criar minha class e dizer se ela implements ou extends.
  2. Subscrever o método run
  3. Dizer o trabalho a ser feito
  4. Criar um objeto da minha class, o qual vai ser o trabalho a ser realizado.
  5. O método start chama o método run() para fazer o trabalho em uma nova pilha.

Obs.: ambos os processos tiveram cinco etapas. Percebeu que “dá no mesmo”?

Regras:

  • O método run() pode ser sobrecarregado, mas não será uma nova thread. Ele vai correr na thread principal.
  • Toda a brincadeira precisa de uma instância da class Thread, independente de implementar Runnable ou extends a Thread.
  • Estado novo – é quando crio um objeto da class thread
  • Chamar start() – somente com objeto Thread.

Como antecipei, vou provar que temos duas threads. Veja o código abaixo:

class NameRun implements Runnable{
	public void run(){
System.out.println("Run by " + Thread.currentThread().getName());
	}}
/* esse código exibe o nome da thread que estiver executando*/
class NameT{
	public static void main(String args[]){
		NameRun r = new NameRun();
		Thread t = new Thread(r);
			t.start();
System.out.println("Run by " + Thread.currentThread().getName());	}}

Thread.currentThread – método estático da class Thread, o qual pega o thread em execução.

getName() – retorna o nome da thread. Observe que toda thread que você criar, o compilador dará um nome a ela. Caso queira alterar o nome, faça isso no código acima.

t.setName(“Zebra”); ou seja InstanciaThread.setName(” “);

Por que não há garantias a respeito de Threads?

Simples. Por que quem decide tudo é o agendador a jvm, e existem alguns métodos que podem influenciar nas ações de threads mais nada é garantido.

Os estados das threads:

Novo – isso quando crio um objeto Thread: Thread t = new Thread(). Aqui o objeto é criado, mas ainda não está rodando. (método run()).

Executável – é quando dou um start() no meu objeto Thread: t.start(). Mas nada garante que quando dermos start o método run() irá executar. Quem decide isso é o agendador. Existem N fatores para ele não executar, como por exemplo ter uma prioridade menor que outro thread em execução.

Execução – aqui é quando a thread está “mandando ver” no método run. Tudo que tiver nele, está sendo executado.

Inativo – é quando o método run() termina e o objeto thread se torna inativo para voltar a executar o run novamente, mas mesmo assim ele é um objeto thread e pode chamar outros métodos, exceto o método run. Caso chame start duas vezes com o mesmo objeto thread, uma exceção vai ocorrer. Quando uma thread está inativa, existe uma frase para ele: “Eu vejo Thread Mortos”.

Suspensão/Bloqueio/Espera – é quando você quer influenciar na execução de uma thread. Por exemplo, posso tentar dar uma suspensão de 5 minutos na minha thread, ou seja, ela vai ficar sem executar por 5 minutos. É semelhante à suspensão no colégio. 10 dias sem aparecer por lá.

Bom, não vou explicar todos nessa coluna, senão vai ficar cansativo. Vou explicar apenas como suspendermos uma thread. Mas porque daria uma suspensão em thread? Por achar que ela está executando demais uma determinada ação.

Exemplo: achar que a thread está fazendo muitos downloads e não está deixando outra thread executar.

Método static Sleep – class Thread

Responsável por fazer a thread “dormir”. Ao usar ele, lembre-se daquele timer que temos na TV para desligar em um tempo X. Quando fazemos isso na TV, dizemos ao sistema da TV que ela vai ficar ligada até o tempo escolhido. Mas pode ser interrompido (se eu desligar a TV).

Neste método sleep, ele lança uma excessão verificada caso for interrompido.

public class Tslep extends Thread {
	Tslep(String s){
		super(s);
	}
	public void run(){
		for(int z=0;z<5;z++){
		System.out.println(Thread.currentThread().getName());
		try{
			Thread.sleep(1000);
		}catch(InterruptedException e){e.printStackTrace();}
	}}

	public static void main(String[] args) {
		Tslep ts = new Tslep("Carlos");
		Tslep ts2 = new Tslep("maria");
			ts.start();
			ts2.start();			
	}
/* o resultado aqui não é garantido, quando um thread é despertado
 * ele pode ou não pode voltar à execução, mas ele fica no estado
 * executável aguardando ser chamado pelo agendador. Mas todos os
 * threads são executados alternados
 */
}

Observe que minha thread dormiu e outra foi chamada. Depois uma dormiu e a outra acordou e dormiu novamente.

Bom, isso é um pouco de threads. Se você se sentiu confuso, tente implementar isso na mão e fazer mais exercícios. Existem muitos tópicos que não abordei, mais métodos, recursos com a sincronização, método wait e notify – isso é fundamental também. Enfim, threads daria um livro e muitas teses. Tentei passar um pouco e espero ter ajudado. Vou deixar alguns exercícios abaixo, de acordo com o artigo abaixo.

Pontos importantes analisar sobre threads :

  1. A ordem que objetos são instanciados não é a mesma ordem que vai ser executado
  2. Não há garantias sobre threads. O agendador que dita às coisas.
  3. Não importa extends ou implementar. Somente posso chamar start de um objeto Thread.
Exercícios threads.
  1. Crie uma class que extends a Thread e, no trabalho a ser executado, faça a soma dos números de 1 a 10. Esse processo deve ser executado em uma nova pilha.
  2. Crie uma class que implements runnable e o trabalho a ser feito é que ela conte de 1 à 15 e, quando um número impar for encontrado, a thread entra em suspensão e depois, quando concluir a contagem, informe quantas vezes a thread entrou em suspensão.
  3. Desenvolva uma class que tenha quatro threads, cada uma com o nome diferente, e o trabalho a ser feito em uma nova pilha seja imprimir o nome das threads.

Abraços a todos e até semana que vem!