7. Threads

            Threads constituem uma característica bastante relevante da linguagem Java. A incorporação dos conceitos de sincronização e variáveis de condição dentro da própria linguagem permite que programadores médios consigam utilizar conceitos de computação concorrente de forma bem facilitada, o que possibilita uma melhoria de performance dos programas. Neste capítulo veremos o que são threads, analisaremos seus estados e métodos básicos e aprenderemos a inserir threads em applets.

 

7.1. O que são threads?

            Uma thread pode ser definido como “um fluxo de controle seqüencial isolado dentro de um programa”. Como um programa seqüencial qualquer, uma thread tem um começo, um fim e uma seqüência de comandos. Entretanto, uma thread em Java não é um programa, não executa sozinho, executa dentro de um programa.

            Threads permitem que um programa simples possa executar várias tarefas diferentes ao mesmo tempo, independentemente umas das outras.

            Programas multithreaded são programas que contém várias threads, executando tarefas distintas, simultaneamente. O browser HotJava, implementado em Java, é um exemplo. Da mesma forma que o Netscape, com o HotJava você pode fazer um scroll em uma página enquanto carrega uma imagem ou executa vários applets ao mesmo tempo.

            Em Java, threads são cidadãos de primeira ordem, se constituindo de instâncias da classe Thread que fornecem suporte a comunicação concorrente. A classe Thread provê os métodos necessários para criar e controlar threads (independentemente da plataforma usada) e executá-los concorrentemente. A real implementação de threads é feita pelo sistema operacional.

            O corpo de uma thread é o seu método run(), e é nele que são executadas as tarefas às quais thread se destina. Podemos implementar threads de duas maneiras (ambas suportadas pelos construtores da classe Thread):

·       Criando uma subclasse da classe Thread e definindo o seu método run() de maneira adequada à realização da tarefa do thread.

·       Criando uma instância de Thread que recebe como parâmetro um objeto que implemente a interface Runnable - esse objeto providenciará o método run() para a thread.

                A linguagem Java fornece meios para criarmos threads como daemons, agruparmos threads, sincronizá-los e controlar suas prioridades.

 

7.2. Os estados de uma thread

 

 

·      New Thread

            Inicialização da thread - feita através do construtor Thread().

class MyThreadClass extends Thread {

       ...

}

...

MyThreadClass myThread = new MyThreadClass();

 

Neste estado, nenhum recurso do sistema foi alocado para o thread ainda, assim, a partir daqui, tudo que você pode fazer é um start(), para ativar a thread, ou um stop(), para “matá-lo”. A chamada de qualquer outro método não faz sentido e levantará a exceção IllegalThreadStateException.

 

·      Runnable

            Este é o estado em que o thread está pronto para rodar. O método start() requisita os recursos do sistema necessários para rodar a thread e chama o seu método run(). O método run() é a “alma” de um thread; é neste método que definimos o que a thread vai executar.

Thread myThread = new MyThreadClass();

myThread.start();

            Falamos em Runnable, ao invés de Running, porque a thread pode não estar realmente sendo executada. Imagine um computador com um único processador - seria impossível executar todas as threads ao mesmo tempo. O que ocorre é que a CPU deve ser escalonada entre as várias threads. Quando uma thread está Running, ela está também Runnable, as instruções do seu método run() é que estão sendo executadas pela CPU.

 

·      Not Runnable

            O estado Not Runnable significa que a thread está impedida de executar por alguma razão. Existem 4 maneiras de uma thread ir para o estado Not Runnable.

1.    receber a mensagem suspend();

2.    receber a mensagem sleep();

3.    a thread bloqueia, esperando I/O;

4.    a thread usa seu método wait() para esperar por uma variável de condição.


 

            O exemplo abaixo coloca o applet myThread para dormir por 10 segundos:

 

Thread myThread = new MyThreadClass();

myThread.start();

try {

      myThread.sleep(10000);

} catch (InterruptedException e) { }

 

            Cada uma destas maneiras tem a sua forma específica de sair do estado Not Runnable.

1.    se a thread foi suspensa, alguém precisa mandar-lhe a mensagem resume();

2.    se a thread foi posta para dormir, ela voltará a ser Runnable quando o número de milisegundos determinado passar;

3.    se a thread está bloqueada, esperando por I/O, a operação precisa ser completada;

4.    se a thread está esperando por uma variável de condição, o objeto que a retém precisa liberá-la, através de um notify() ou de um notifyAll()

 

·      Dead

            Uma thread pode morrer de “causas naturais” (quando o seu método run() acaba normalmente) ou pode ser morto pelo método stop().

            É possível controlar a ordem de execução de várias threads definindo prioridades para eles. O escalonador de threads do Java segue a seguinte regra: a qualquer instante, a thread corrente é a de maior prioridade. Para que a thread de maior prioridade ceda CPU a outra thread, ele precisa enviar para si o método yield(), ou, entrar no estado Not Runnable. Caso contrário, ele irá executar até que termine seu método run().

            Para descobrir a prioridade de uma thread, podemos usar o método getPriority() e, para defini-la setPriority(n), onde n é um inteiro de 1 a 10 (10 representando a prioridade máxima).

 

7.3. Threads em Applets

            Até agora nós vimos como trabalhar com threads criadas a partir da classe Thread ou de uma classe que herde da classe Thread. Sabemos que esta classe provê os métodos básicos para se lidar com threads (run(), start(), stop(), sleep(), etc.).

            Suponha que você queira, agora, implementar uma thread dentro de uma applet. Por exemplo, suponha que você quer fazer uma applet relógio, que atualiza o seu display a cada segundo. A classe que vai implementar o seu relógio precisa ser uma subclasse da classe Applet para herdar todas as facilidades oferecidas por ela. Como fazê-la, então, herdar também da classe Thread? A interface Runnable é a solução!

            Qualquer objeto que implemente a interface Runnable pode utilizar o seu método run() para ser executado como uma thread.

 

class Clock extends Applet implements Runnable {

      ....

}

      A applet Clock precisa, agora, criar a sua própria thread. Isto é feito no seu método start()

public void start() {

      if ( clockThread == null) {

            clockThread  = new Thread(this, “Clock”);

            clockThread.start();

      }

}

 

            Observe a chamada ao construtor Thread(this, “Clock”). O construtor precisa receber como primeiro argumento um objeto que implemente a interface Runnable, este objeto é que vai fornecer o método run() da thread clockThread.

 

public void run() {

      while (clockThread != null) {

            repaint();

            try {

                  clockThread.sleep(1000);

            } catch (InterruptedException e) { }

      }

}

            No método stop() do applet Clock, temos que chamar também o método stop() da thread clockThread, caso contrário, a thread vai continuar executando e consumindo recursos mesmo depois que sairmos da página da applet.

public void stop() {

      clockThread.stop();

      clockThread = null;

}

            Se você revisitar a página, o start() da applet Clock é chamado novamente e uma nova thread é inicializada.

7.4. Herdando de Thread x Implementando Runnable

            Existem duas maneiras de implementar threads:

1.    Herdando da classe Thread ou de subclasses da classe Thread.

2.    Implementando a interface Runnable e criando uma thread (passando o objeto que implementa Runnable como argumento).

Qual opção utilizar?

            Se você precisa estender outra classe (o exemplo mais comum é a classe Applet), use Runnable. Entretanto, se você está planejando apenas sobrepor o método run(), e mais nenhum outro método de Thread, use Runnable. Classes não devem herdar de outras classes, a menos que o programador pretenda modificar ou aprimorar o comportamento fundamental da classe.

 

 


 

 

            Abaixo o código completo da applet Clock:

/*

 * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.

 *

 * Permission to use, copy, modify, and distribute this software

 * and its documentation for NON-COMMERCIAL purposes and without

 * fee is hereby granted provided that this copyright notice

 * appears in all copies. Please refer to the file "copyright.html"

 * for further important copyright and licensing information.

 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF

 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED

 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A

 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR

 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR

 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.

 */

import java.awt.Graphics;

import java.util.Date;

 

public class Clock extends java.applet.Applet implements Runnable {

 

    Thread clockThread = null;

 

    public void start() {

        if (clockThread == null) {

            clockThread = new Thread(this, "Clock");

            clockThread.start();

        }

    }

    public void run() {

        // loop terminates when clockThread is set to null in stop()

        while (Thread.currentThread() == clockThread) {

            repaint();

            try {

                clockThread.sleep(1000);

            } catch (InterruptedException e){

            }

        }

    }

    public void paint(Graphics g) {

        Date now = new Date();

        g.drawString(now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(), 5, 10);

    }

    public void stop() {

        clockThread = null;

    }

}


 

8. Procure Saber Mais Sobre

8.1. URL

                Para aqueles que gostariam de interligar suas Applets com outros recursos da Internet, o Java contém classes especificas para isto.

8.2. Fila, Pilha, Tabela Hash

            A maioria das estruturas abstratas de dados já estão implementadas no Java, veja as bibliotecas contidas em java.util.

8.3. Javadoc

                Fazer a documentação de um sistema sempre foi um problema. Na linguagem Java existe um gerador de documentação em HTML. O Javadoc gera documentação de: Packages, classes, interfaces, exceções, métodos e variáveis.

8.4. Ambientes de Programação/Debugação

            Além do JDK, existem vários outros ambientes de programação e depuração para Java, abaixo relacionamos os mais conhecidos:

Symantec Espresso:

Ambiente completo de desenvolvimento para Windows 95, além de um gerenciador de projeto, contém um poderoso.

Borland Latte:

O Latte está ainda em desenvolvimento pela Borland. Este ambiente está sendo desenvolvido totalmente em Java, isto vai possibilitar a Borland vender o Latte para todas as plataformas.

JavaMaker:

Desenvolvido por Heechang Choi, roda sobre Windows 95 e NT. É muito simples, pequeno e fácil de utilizar.

J++:

Ambiente de desenvolvimento ainda em fase de desenvolvimento pela Microsoft.

Cosmo Code:

Um dos mais interessantes ambientes já montados, faz parte do Cosmo Web system. Cosmo Code é avaliavel para estações Silicon Graphics.


 

Referências Bibliográficas

 

Alcantara, Andreia Almeida. Anais da XV JAI - Minicurso Java. Departamento de Informática UFPE, 1996.

Damasceno Jr, Américo. Aprendendo Java - Programação na Internet. Editora Érica, 1996.

Lemay, Laura e Perkins, Charles. Teach Yourself Java in 21 Days. Sams net Group, 1996.

Java API Documentation. Sun Microsystems, 1995.

Java Unleashed. Sams net Group, 1996.

 

Free Web Hosting