Vous êtes sur la page 1sur 90

1

23
Multithreading
2005 by Pearson Education do Brasil

OBJETIVOS
Neste captulo, voc aprender: O que so as threads e por que elas so teis. Como as threads permitem gerenciar atividades concorrentes. O ciclo de vida de uma thread. Prioridades e agendamento de threads. Como criar e executar Runnables. Sincronizao de threads. O que so relacionamentos produtor/consumidor e como so implementados com multithreading. Como exibir a sada de mltiplas threads em uma GUI Swing. Sobre Callable e Future.
2005 by Pearson Education do Brasil

23.1 23.2 23.3 23.4 23.5 23.6 23.7 23.8

Introduo Estados de thread: Classe Thread Prioridades de thread e agendamento de thread Criando e executando threads Sincronizao de thread Relacionamento entre produtor e consumidor sem sincronizao Relacionamento entre produtor e consumidor com sincronizao Relacionamento de produtor/consumidor: Buffer circular

23.9

Relacionamento de produtor/consumidor: ArrayBlockingQueue

23.10 Multithreading com GUI 23.11 Outras classes e interfaces em java.util.concurrent

23.12 Monitores e bloqueios de monitor


23.13 Concluso
2005 by Pearson Education do Brasil

23.1 Introduo
Multithreading:
Fornece mltiplas threads de execuo para a aplicao.
Permite que programas realizem tarefas concorrentemente. Com freqncia, exige que o programador sincronize as threads para que funcionem corretamente.

2005 by Pearson Education do Brasil

Dica de desempenho 23.1


Um problema com aplicativos de uma nica thread que atividades longas devem ser concludas antes que outras atividades se iniciem. Em um aplicativo com mltiplas threads, as threads podem ser distribudas por mltiplos processadores (se estiverem disponveis) de modo que mltiplas tarefas so realizadas concorrentemente e o aplicativo pode operar de modo mais eficiente. Multithreading tambm pode aumentar o desempenho em sistemas de um nico processador que simula a concorrncia quando uma thread no puder prosseguir, outra pode utilizar o processador.

2005 by Pearson Education do Brasil

Dica de portabilidade 23.1


Ao contrrio das linguagens que no tm capacidades de multithreading integradas (como C e C++) e, portanto, devem fazer chamadas noportveis para primitivos de multithreading do sistema operacional, o Java inclui primitivos de multithreading como parte da prpria linguagem e de suas bibliotecas. Isso facilita a manipulao de threads de maneira portvel entre plataformas.

2005 by Pearson Education do Brasil

23.2 Estados de thread: Classe Thread


Estados de thread:
Estado novo:
Uma nova thread inicia seu ciclo de vida no estado novo. Permanece nesse estado at o programa iniciar a thread, colocando-a no estado executvel

Estado executvel:
Uma thread que entra nesse estado est executando sua tarefa.

Estado em espera:
Uma thread entra nesse estado a fim de esperar que uma outra thread realize uma tarefa.

2005 by Pearson Education do Brasil

23.2 Estados de thread: Classe Thread (Continuao)


Estados de thread:
Estado de espera cronometrada:
Uma thread entra nesse estado para esperar uma outra thread ou para transcorrer um determinado perodo de tempo. Uma thread nesse estado retorna ao estado executvel quando ela sinalizada por uma outra thread ou quando o intervalo de tempo especificado expirar.

Estado terminado:
Uma thread executvel entra nesse estado quando completa sua tarefa.

2005 by Pearson Education do Brasil

Figura 23.1 | Diagrama de estado do ciclo de vida da thread.

2005 by Pearson Education do Brasil

23.2 Estados de thread: Classe Thread (Continuao)


Viso do sistema operacional do estado executvel:
Estado pronto:
Uma thread nesse estado no est esperando uma outra thread, mas est esperando que o sistema operacional atribua a thread a um processador.

10

Estado em execuo:
Uma thread nesse estado tem atualmente um processador e est executando.

Uma thread no estado em execuo freqentemente utiliza uma pequena quantidade de tempo de processador chamada frao de tempo, ou quantum, antes de migrar de volta para o estado pronto.

2005 by Pearson Education do Brasil

11

Figura 23.2 | Visualizao interna do sistema operacional do estado executvel do Java.

2005 by Pearson Education do Brasil

23.3 Prioridades de thread e agendamento de thread


Prioridades:
Cada thread Java tem uma prioridade.
As prioridades do Java esto no intervalo entre MIN_PRIORITY (uma constante de 1) e MAX_PRIORITY (uma constante de 10).

12

As threads com uma prioridade mais alta so mais importantes e tero um processador alocado antes das threads com uma prioridade mais baixa. A prioridade-padro NORM_PRIORITY (uma constante de 5).

2005 by Pearson Education do Brasil

23.3 Prioridades de thread e agendamento de thread (Cont.)


Agendador de thread:
Determina qual thread executada em seguida.
Uma implementao simples executa threads com a mesma prioridade no estilo rodzio. Threads de prioridade mais alta podem fazer preempo da thread atualmente em execuo. Em alguns casos, as threads de prioridade alta podem adiar indefinidamente threads de prioridade mais baixa o que tambm conhecido como inanio.

13

2005 by Pearson Education do Brasil

14

Dica de portabilidade 23.2


O agendamento de thread dependente de plataforma um aplicativo que utiliza multithreading poderia comportar-se diferentemente em implementaes separadas do Java.

2005 by Pearson Education do Brasil

15

Dica de portabilidade 23.3


Ao projetar applets e aplicativos que utilizam threads, voc deve considerar as capacidades de threading de todas as plataformas em que as applets e os aplicativos sero executados.

2005 by Pearson Education do Brasil

16

Figura 23.3 | Agendamento de prioridade de threads.


2005 by Pearson Education do Brasil

17

23.4 Criando e executando threads


A interface Runnable:
Meio preferido de criar um aplicativo com multithreads. Declara o mtodo run.
Executado por um objeto que implementa a interface Executor.

Interface Executor:
Declara o mtodo execute. Cria e gerencia um grupo de threads chamado pool de threads.

2005 by Pearson Education do Brasil

23.4 Criando e executando threads (Continuao)


Interface ExecutorService:
uma subinterface de Executor que declara outros mtodos para gerenciar o ciclo de vida de um Executor. Pode ser criada utilizando os mtodos static da classe Executors. O mtodo shutdown finaliza as threads quando as tarefas so concludas.

18

Classe Executors:
O mtodo newFixedThreadPool cria um pool que consiste em um nmero fixo de threads. O mtodo newCachedThreadPool cria um pool que cria novas threads conforme necessrio.

2005 by Pearson Education do Brasil

1 // Fig. 23.4: PrintTask.java 2 // Classe PrintTask dorme por um tempo aleatrio de 0 a 5 segundos 3 import java.util.Random; 4 5 class PrintTask implements Runnable 6 { 7 8 9 10 11 12 13 14 15 16 17 18 19

19

Resumo

PrintTask.java

(1 de 2)

private int sleepTime; // tempo de adormecimento aleatrio para a thread private String threadName; // nome da thread private static Random generator = new Random(); // atribui nome thread public PrintTask( String name ) { threadName = name; // configura nome da thread // seleciona tempo de adormecimento aleatrio entre 0 e 5 segundos sleepTime = generator.nextInt( 5000 ); } // fim do construtor PrintTask

Implementa runnable para criar uma thread separada

2005 by Pearson Education do Brasil

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

// mtodo run o cdigo a ser executado pela nova thread public void run() { try // coloca a thread para dormir a pela quantidade de tempo sleepTime PrintTask.java { System.out.printf( "%s going to sleep for %d milliseconds.\n", threadName, sleepTime ); Thread.sleep( sleepTime ); // coloca a thread para dormir } // fim do try // se a thread foi interrompida enquanto dormia, imprime o rastreamento de pilha catch ( InterruptedException exception ) { exception.printStackTrace(); } // fim do catch // imprime o nome da thread System.out.printf( "%s done sleeping\n", threadName ); } // fim do mtodo run

20

Resumo

(2 de 2)

39 } // fim da classe PrintTask

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

// Fig. 23.5: RunnableTester.java // Impresso de mltiplas threads em diferentes intervalos. import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; public class RunnableTester { public static void main( String[] args ) { // cria e nomeia cada executvel PrintTask task1 = new PrintTask( "thread1" ); PrintTask task2 = new PrintTask( "thread2" ); PrintTask task3 = new PrintTask( "thread3" ); System.out.println( "Starting threads" ); // cria ExecutorService para gerenciar threads ExecutorService threadExecutor = Executors.newFixedThreadPool( 3 ); // inicia threads e coloca no estado executvel threadExecutor.execute( task1 ); // inicia task1 threadExecutor.execute( task2 ); // inicia task2 threadExecutor.execute( task3 ); // inicia task3 threadExecutor.shutdown(); // encerra as threads trabalhadoras

21

Resumo
RunnableTester .java

(1 de 2)

2005 by Pearson Education do Brasil

27 28

System.out.println( "Threads started, main ends\n" ); } // fim do main

22

29 } // fim da classe RunnableTester Starting threads Threads started, main ends thread1 thread2 thread3 thread3 thread1 thread2 going to sleep for 1217 milliseconds going to sleep for 3989 milliseconds going to sleep for 662 milliseconds done sleeping done sleeping done sleeping

Resumo
RunnableTester .java

(2 de 2)

Starting threads thread1 going to sleep for 314 milliseconds thread2 going to sleep for 1990 milliseconds Threads started, main ends thread3 thread1 thread2 thread3 going to sleep for 3016 milliseconds done sleeping done sleeping done sleeping

2005 by Pearson Education do Brasil

23

23.5 Sincronizao de thread


Sincronizao de threads:
Fornecido ao programador com excluso mtua.
Acesso exclusivo a um objeto compartilhado.

Implementado no Java utilizando bloqueios.

Interface Lock:
O mtodo lock obtm o bloqueio, impondo a excluso mtua. O mtodo unlock libera o bloqueio.

A classe ReentrantLock implementa a interface Lock.

2005 by Pearson Education do Brasil

24

Dica de desempenho 23.2


Utilizar um Lock com uma diretiva relativamente justa evita o adiamento indefinido, mas tambm pode reduzir significativamente a eficincia geral de um programa. Por causa da grande diminuio de desempenho, os bloqueios imparciais s so necessrios em circunstncias extremas.

2005 by Pearson Education do Brasil

23.5 Sincronizao de thread (Continuao)


Variveis de condio:
Se uma thread que mantm o bloqueio no puder continuar a sua tarefa at uma condio ser satisfeita, a thread pode esperar uma varivel de condio. Criadas chamando newCondition do mtodo Lock. Representadas por um objeto que implementa a interface Condition.

25

Interface Condition:
Declara os mtodos: await, para fazer uma thread esperar; signal, para acordar uma thread em espera; e signalAll, para acordar todas as threads em espera.

2005 by Pearson Education do Brasil

26

Erro comum de programao 23.1


O impasse (deadlock) ocorre quando uma thread em espera (vamos cham-la de thread1) no pode prosseguir porque est esperando (direta ou indiretamente) outra thread (vamos cham-la de thread2) prosseguir; simultaneamente, a thread2 no pode prosseguir porque est esperando (direta ou indiretamente) a thread1 prosseguir. Como duas threads esto esperando uma outra, as aes que permitiriam a cada thread continuar a execuo nunca ocorrem.

2005 by Pearson Education do Brasil

27

Dica de preveno de erro 23.1


Quando mltiplas threads manipulam um objeto compartilhado utilizando bloqueios, assegure de que, se uma thread chamar o mtodo await para entrar no estado de espera por uma varivel de condio, uma thread separada por fim chamar o mtodo Condition signal para fazer a transio da thread em espera pela varivel de condio de volta para o estado executvel. (Continua...)

2005 by Pearson Education do Brasil

28

Dica de preveno de erro 23.1


Se mltiplas threads podem estar esperando a varivel de condio, uma thread separada pode chamar o mtodo Condition signalAll como uma salvaguarda para assegurar que todas as threads na espera tenham outra oportunidade de realizar suas tarefas. Se isso no for feito, o adiamento indefinido ou impasse poderia ocorrer.

2005 by Pearson Education do Brasil

29

Observao de engenharia de software 23.1


O bloqueio que ocorre com a execuo dos mtodos lock e unlock poderia levar a um impasse se os bloqueios nunca forem liberados. As chamadas para mtodo unlock devem ser colocadas em blocos finally para assegurar que os bloqueios sejam liberados e evitar esses tipos de impasses.

2005 by Pearson Education do Brasil

30

Dica de desempenho 23.3


A sincronizao para alcanar a preciso em programas de mltiplas threads pode tornar a execuo de programas mais lenta, como resultado de overhead de thread e da transio freqente de threads entre os estados de espera e executvel. No h, entretanto, muito a dizer sobre programas multiencadeados altamente eficientes, mas incorretos!

2005 by Pearson Education do Brasil

31

Erro comum de programao 23.2


um erro se uma thread emitir um await, um signal ou um signalAll em uma varivel de condio sem adquirir o bloqueio dessa varivel de condio. Isso causa uma IllegalMonitorStateException.

2005 by Pearson Education do Brasil

23.6 Relacionamento entre produtor e consumidor sem sincronizao


Relacionamento produtor/consumidor:
O produtor gera dados e os armazena na memria compartilhada.
O consumidor l os dados da memria compartilhada. A memria compartilhada chamada buffer.

32

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8

// Fig. 23.6: Buffer.java // Interface Buffer especifica mtodos chamados por Producer e Consumer.

33

Resumo
Bbuffer.java

public interface Buffer { public void set( int value ); // coloca o valor int no Buffer public int get(); // retorna o valor int a partir do Buffer } // fim da interface Buffer

Figura 23.6

| Interface Buffer utilizada nos exemplos de


2005 by Pearson Education do Brasil

produtor/consumidor.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

// Fig. 23.7: Producer.java // O mtodo run do Producer armazena os valores de 1 a 10 no buffer. import java.util.Random; public class Producer implements Runnable { private static Random generator = new Random(); private Buffer sharedLocation; // referncia a // construtor public Producer( Buffer shared ) { sharedLocation = shared; } // fim do construtor Producer // armazena valores de 1 a 10 em sharedLocation public void run() { int sum = 0;

34

Resumo
Producer.java

Implementa a interface runnable (1 de 2) objeto de modo que o produtor possa ser compartilhado executado em uma thread separada

Declara o mtodo run para satisfazer a interface

2005 by Pearson Education do Brasil

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

for ( int count = 1; count <= 10; count++ ) { try // dorme de 0 a 3 segundos, ento coloca valor em Buffer { Thread.sleep( generator.nextInt( 3000 ) ); // thread sleep sharedLocation.set( count ); // configura valor no buffer sum += count; // incrementa soma de valores System.out.printf( "\t%2d\n", sum ); } // fim do try catch ( InterruptedException exception ) { exception.printStackTrace(); } // fim do catch } // fim do for System.out.printf( "\n%s\n%s\n", "Producer done producing.", "Terminating Producer." ); } // fim do mtodo run

35

Resumo
Producer.java

(2 de 2) Dorme por at 3 segundos

// se a thread adormecida interrompida, imprime rastreamento de pilha

40 } // fim da classe Producer

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

// Fig. 23.8: Consumer.java // O mtodo run de Consumer itera dez vezes lendo um valor do buffer. import java.util.Random; public class Consumer implements Runnable { private static Random generator = new Random(); Implementa a interface private Buffer sharedLocation; // referncia a objeto compartilhado // construtor public Consumer( Buffer shared ) { sharedLocation = shared; } // fim do construtor Consumer // l o valor do sharedLocation quatro vezes e soma os public void run() { int sum = 0;

36

Resumo
Consumer.java

runnable de modo que o produtor possa ser (1 de 2) executado em uma thread separada

Declara o mtodo run para satisfazer a interface valores

2005 by Pearson Education do Brasil

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

for ( int count = 1; count <= 10; count++ ) { // dorme de 0 a 3 segundos, l o valor do buffer e adiciona a soma try { Thread.sleep( generator.nextInt( 3000 ) ); sum += sharedLocation.get(); System.out.printf( "\t\t\t%2d\n", sum ); } // fim do try catch ( InterruptedException exception ) { exception.printStackTrace(); } // fim do catch } // fim do for System.out.printf( "\n%s %d.\n%s\n", "Consumer read values totaling", sum, "Terminating Consumer." );

37

Resumo
Consumer.java

(2 de 2)

// se a thread adormecida interrompida, imprime rastreamento at 3 segundos Dorme por de pilha

39 } // fim do mtodo run 40 } // fim da classe Consumer

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

// Fig. 23.9: UnsynchronizedBuffer.java // UnsynchronizedBuffer representa um nico inteiro compartilhado. public class UnsynchronizedBuffer implements Buffer { private int buffer = -1; // compartilhado pelas threads producer e consumer // coloca o valor no buffer public void set( int value ) { System.out.printf( "Producer writes\t%2d", value ); buffer = value; } // fim do mtodo set // retorna o valor do buffer public int get() { System.out.printf( "Consumer reads\t%2d", buffer );

38

Resumo
Unsynchronized Buffer.java

Varivel compartilhada para armazenar dados

Configura o valor do buffer

L o valor do buffer

19 return buffer; 20 } // fim do mtodo get 21 } // fim da classe UnsynchronizedBuffer

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

// Fig 23.10: SharedBufferTest.java // Aplicativo mostra duas threads que manipulam um buffer no-sincronizado. import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SharedBufferTest { public static void main( String[] args ) { // cria novo pool de threads com duas threads ExecutorService application = Executors.newFixedThreadPool( 2 ); // cria UnsynchronizedBuffer para armazenar ints Buffer sharedLocation = new UnsynchronizedBuffer();

39

Resumo
SharedBufferTest .java

(1 de 4)

Cria um UnsynchronizedBuffer compartilhado para que o produtor e o consumidor o utilizem

2005 by Pearson Education do Brasil

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

System.out.println( "Action\t\tValue\tProduced\tConsumed" ); System.out.println( "------\t\t-----\t--------\t--------\n" ); // tenta iniciar as threads produtora e consumidora fornecendo acesso a cada uma // para sharedLocation try { application.execute( new Producer( sharedLocation ) ); application.execute( new Consumer( sharedLocation ) ); } // fim do try catch ( Exception exception ) { exception.printStackTrace(); } // fim do catch

40

Resumo
SharedBufferTest .java

(2 de 4)

Passa o buffer compartilhado tanto para o produtor como para o consumidor

application.shutdown(); // termina aplicativo quando as threads terminam } // fim do main

33 } // fim da classe SharedBufferTest

2005 by Pearson Education do Brasil

Action -----Producer Producer Producer Consumer Producer Consumer Producer Producer Producer Consumer Consumer Producer Consumer Consumer Producer Producer

Value ----writes 1 writes 2 writes 3 reads 3 writes 4 reads 4 writes 5 writes 6 writes 7 reads 7 reads 7 writes 8 reads 8 reads 8 writes 9 writes 10

Produced -------1 3 6

Consumed --------

41

Resumo
SharedBufferTest .java

3 10 7 15 21 28 14 21 36 29 37 45 55

(3 de 4)

Producer done producing. Terminating Producer. Consumer reads 10 Consumer reads 10 Consumer reads 10 Consumer reads 10 Consumer read values totaling 77. Terminating Consumer.

47 57 67 77

2005 by Pearson Education do Brasil

Action -----Consumer Producer Consumer Consumer Consumer Consumer Consumer Producer Consumer Producer Consumer Producer Consumer Producer Producer Consumer

Value ----reads -1 writes 1 reads 1 reads 1 reads 1 reads 1 reads 1 writes 2 reads 2 writes 3 reads 3 writes 4 reads 4 writes 5 writes 6 reads 6

Produced --------

Consumed --------1

42

Resumo
SharedBufferTest .java

1 0 1 2 3 4 3 6 6 9 10 13 15 21 19

(4 de 4)

Consumer read values totaling 19. Terminating Consumer. Producer writes 7 28 Producer writes 8 36 Producer writes 9 45 Producer writes 10 55 Producer done producing. Terminating Producer.

2005 by Pearson Education do Brasil

23.7 Relacionamento entre produtor e consumidor com sincronizao


Relacionamento produtor/consumidor:
Este exemplo utiliza Locks e Conditions para implementar a sincronizao.

43

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

// Fig. 23.11: SynchronizedBuffer.java // SynchronizedBuffer sincroniza acesso a um nico inteiro compartilhado. import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.Condition; public class SynchronizedBuffer implements Buffer { // Bloqueio para controlar sincronizao com esse buffer private Lock accessLock = new ReentrantLock(); // condies para controlar leitura e gravao

44

Resumo

SynchronizedBuffer Cria ReentrantLock para .java excluso mtua

(1 de 5) Cria duas variveis de Condition; uma para gravao e outra para leitura

private Condition canWrite = accessLock.newCondition(); private Condition canRead = accessLock.newCondition(); private int buffer = -1; // compartilhado pelas threads producer e consumer por Buffer compartilhado private boolean occupied = false; // se o buffer estiver ocupadoe // coloca o valor int no buffer public void set( int value ) { accessLock.lock(); // bloqueia esse objeto

produtor

consumidor

Tenta obter o bloqueio antes de configurar o valor dos dados compartilhados

2005 by Pearson Education do Brasil

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

// envia informaes de thread e de buffer para a sada, ento espera try { // enquanto o buffer no estiver vazio, coloca thread no estado de espera while ( occupied ) { System.out.println( "Producer tries to write." ); displayState( "Buffer full. Producer waits." ); } // end while canWrite.await(); // espera at que o buffer esteja vazio Produtor espera

45

Resumo
SynchronizedBuffer .java

at que o(2 de 5) buffer esteja vazio

buffer = value; // configura novo valor de buffer // indica que a produtora no pode armazenar outro valor // at a consumidora recuperar valor atual de buffer occupied = true;

2005 by Pearson Education do Brasil

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

displayState( "Producer writes " + buffer ); // sinaliza a thread que est esperando para ler a partir do buffer canRead.signal(); } // fim do try catch ( InterruptedException exception ) { exception.printStackTrace(); } // fim do catch finally { accessLock.unlock(); // desbloqueia esse objeto } // fim do finally } // fim do mtodo set // retorna valor do buffer public int get() { int readValue = 0; // inicializa de valor lido a partir do buffer accessLock.lock(); // bloqueia esse objeto

46

Resumo
SynchronizedBuffer .java

Sinaliza ao consumidor que ele pode ler um valor

(3 de 5)

Libera o bloqueio sobre os dados compartilhados

Adquire o bloqueio antes de ler um valor

2005 by Pearson Education do Brasil

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

// envia informaes de thread e de buffer para a sada, ento espera try { // enquanto os dados no so lidos, coloca thread em estado de espera while ( !occupied ) { System.out.println( "Consumer tries to read." ); displayState( "Buffer empty. Consumer waits." ); canRead.await(); // espera at o buffer tornar-se cheio O consumidor } // fim do while // indica que a produtora pode armazenar outro valor // porque a consumidora acabou de recuperar o valor do buffer occupied = false; readValue = buffer; // recupera o valor do buffer displayState( "Consumer reads " + readValue );

47

Resumo
SynchronizedBuffer .java

espera at(4 de o que 5) buffer contenha os dados a ler

2005 by Pearson Education do Brasil

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

// sinaliza a thread que est esperando o buffer tornar-se vazio canWrite.signal(); } // fim do try gravar no // se a thread na espera tiver sido interrompida, imprime o rastreamento de pilha catch ( InterruptedException exception ) { exception.printStackTrace(); } // fim do catch finally { accessLock.unlock(); // desbloqueia esse objeto } // fim do finally return readValue; } // fim do mtodo get // exibe a operao atual e o estado de buffer public void displayState( String operation ) { System.out.printf( "%-40s%d\t\t%b\n\n", operation, buffer, occupied );

48

Sinaliza ao produtor que ele pode buffer

Resumo

SynchronizedBuffer .java

(5 de 5)
Libera o bloqueio sobre os dados compartilhados

101 } // fim do mtodo displayState 102 } // fim da classe SynchronizedBuffer

2005 by Pearson Education do Brasil

49

Erro comum de programao 23.3


Faz chamadas ao mtodo Lock unlock em um bloco finally. Se uma exceo for lanada, o desbloqueio ainda deve ser chamado ou o impasse pode ocorrer.

2005 by Pearson Education do Brasil

50

Observao de engenharia de software 23.2


Sempre invoque o mtodo await em um loop que testa uma condio apropriada. possvel que uma thread entre novamente no estado executvel antes que a condio que ela estava esperando seja satisfeita. Testar a condio novamente assegura que a thread no executar de maneira errada se ela tiver sido sinalizada anteriormente.

2005 by Pearson Education do Brasil

51

Erro comum de programao 23.4


Esquecer de sinalizar (signal) uma thread que est esperando por uma condio um erro de lgica. A thread permanecer no estado de espera, o que a impedir de continuar trabalhando. Essa espera pode levar a um adiamento indefinido ou a um impasse.

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

// Fig 23.12: SharedBufferTest2.java // Aplicativo mostra duas threads que manipulam um buffer sincronizado. import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SharedBufferTest2 { public static void main( String[] args ) { // cria novo pool de threads com duas threads ExecutorService application = Executors.newFixedThreadPool( 2 ); // cria SynchronizedBuffer para armazenar ints Buffer sharedLocation = new SynchronizedBuffer();

52

Resumo
SharedBufferTest2 .java

(1 de 4)

Cria o SynchronizedBuffer a ser compartilhado entre produtor e consumidor

2005 by Pearson Education do Brasil

16 17 18 19 20 21 22 23 24 25 26 27 28

System.out.printf( "%-40s%s\t\t%s\n%-40s%s\n\n", "Operation", "Buffer", "Occupied", "---------", "------\t\t--------" ); try // tenta iniciar a produtora e a consumidora { application.execute( new Producer( sharedLocation ) ); application.execute( new Consumer( sharedLocation ) ); } // fim do try Executa catch ( Exception exception ) { exception.printStackTrace(); } // fim do catch

53

Resumo
SharedBufferTest2 .java

o produtor e o consumidor em threads separadas de 4) (2

29 application.shutdown(); 30 } // fim do main 31 } // fim da classe SharedBufferTest2

2005 by Pearson Education do Brasil

Operation --------Producer writes 1 Producer tries to write. Buffer full. Producer waits. Consumer reads 1 Producer writes 2 Producer tries to write. Buffer full. Producer waits. Consumer reads 2 Producer writes 3 Consumer reads 3 Producer writes 4 Consumer reads 4 Consumer tries to read. Buffer empty. Consumer waits. Producer writes 5 Consumer reads 5 Consumer tries to read. Buffer empty. Consumer waits.

Buffer -----1

Occupied -------true

54

Resumo
SharedBufferTest2 .java

1 1 2

true false true

(3 de 4)

2 2 3 3 4 4

true false true false true false

4 5 5

false true false

false

2005 by Pearson Education do Brasil

Producer writes 6 Consumer reads 6 Producer writes 7 Consumer reads 7 Producer writes 8 Consumer reads 8 Producer writes 9 Consumer reads 9 Producer writes 10

6 6 7 7 8 8 9 9 10

true false true false true false true false true

55

Resumo
SharedBufferTest2 .java

(4 de 4)

Producer done producing. Terminating Producer. Consumer reads 10

10

false

Consumer read values totaling 55. Terminating Consumer.

2005 by Pearson Education do Brasil

23.8 Relacionamento de produtor/ consumidor: Buffer circular


Buffer circular:
Fornece espao extra em buffer no qual o produtor pode colocar valores e o consumidor pode ler valores.

56

2005 by Pearson Education do Brasil

57

Dica de desempenho 23.4


Mesmo ao utilizar um buffer circular, possvel que uma thread produtora possa preencher o buffer, o que foraria a thread produtora a esperar at que uma consumidora consumisse um valor para liberar um elemento no buffer. De maneira semelhante, se o buffer estiver vazio em qualquer dado momento, a thread consumidora deve esperar at que a produtora produza outro valor. A chave para utilizar um buffer circular otimizar o tamanho do buffer para minimizar a quantidade de tempo de espera da thread.

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

// Fig. 23.13: CircularBuffer.java // SynchronizedBuffer sincroniza acesso a um nico inteiro compartilhado. import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.Condition; public class CircularBuffer implements Buffer { private Lock accessLock = new ReentrantLock(); // condies para controlar leitura e gravao private Condition canWrite = accessLock.newCondition(); private Condition canRead = accessLock.newCondition(); private int[] buffer = { -1, -1, -1 }; private int occupiedBuffers = 0; // conta nmero de buffers utilizados private int writeIndex = 0; // ndice para escrever o prximo valor private int readIndex = 0; // ndice para ler o prximo valor // coloca o valor no buffer public void set( int value ) { accessLock.lock(); // bloqueia esse objeto

58

Resumo

CircularBuffer .java Bloqueia para impor excluso mtua

// Bloqueio para controlar sincronizao com esse buffer

Variveis de condio (1 de 5) para controlar a gravao e leitura Buffer circular; fornece trs espaos para dados

Obtm o bloqueio antes de gravar dados no buffer circular

2005 by Pearson Education do Brasil

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

// envia informaes de thread e de buffer para a sada, ento espera try { // enquanto no houver posies vazias, pe o thread no estado de espera while ( occupiedBuffers == buffer.length ) { System.out.printf( "All buffers full. Producer waits.\n" ); canWrite.await();//espera at um elemento buffer ser liberado } // fim do while

59

Resumo
CircularBuffer .java

Espera at um espao de(2 de 5)estar vazio buffer Atualiza o ndice; essa instruo impe a circularidade do buffer

buffer[ writeIndex ] = value; // configura novo valor de buffer // atualiza ndice de gravao circular writeIndex = ( writeIndex + 1 ) % buffer.length; occupiedBuffers++; // mais um elemento buffer

Sinaliza a thread em espera de que agora ela est cheio pode ler dados no buffer

displayState( "Producer writes " + buffer[ writeIndex ] ); canRead.signal(); // sinaliza threads que esto esperando para ler o buffer } // fim do try catch ( InterruptedException exception ) { exception.printStackTrace(); } // fim do catch finally { accessLock.unlock(); // desbloqueia esse objeto } // fim do finally } // fim do mtodo set

Libera o bloqueio

2005 by Pearson Education do Brasil

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76

// retorna valor do buffer public int get() { int readValue = 0; // inicializa de valor lido a partir do buffer accessLock.lock(); // bloqueia esse objeto // espera at que o buffer tenha dados, ento l o valor ler um valor .java try { (3 de 5) // enquanto os dados no so lidos, coloca thread em estado de espera gravado no Espera um valor a ser while ( occupiedBuffers == 0 ) buffer { System.out.printf( "All buffers empty. Consumer waits.\n" ); canRead.await(); // espera at que um elemento buffer seja preenchido } // fim do while readValue = buffer[ readIndex ]; // l valor do buffer // atualiza ndice de leitura circular readIndex = ( readIndex + 1 ) % buffer.length;

60

Resumo
Bloqueia o objeto antes de tentar CircularBuffer

Atualiza o ndice de leitura; essa instruo impe a circularidade do buffer

2005 by Pearson Education do Brasil

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

occupiedBuffers--; // mais um elemento buffer est vazio displayState( "Consumer reads " + readValue ); canWrite.signal(); // sinaliza threads que esto esperando para gravar no buffer

61

Resumo
CircularBuffer .java

} // fim do try Sinaliza threads que esto // se a thread na espera tiver sido interrompida, imprime o rastreamento para gravar no buffer esperando de pilha catch ( InterruptedException exception ) { exception.printStackTrace(); } // fim do catch finally { accessLock.unlock(); // desbloqueia esse objeto } // fim do finally return readValue; } // fim do mtodo get // exibe operao atual e o estado do buffer public void displayState( String operation ) { // gera sada de operao e nmero de buffers ocupados System.out.printf( "%s%s%d)\n%s", operation, " (buffers occupied: ", occupiedBuffers, "buffers: " ); for ( int value : buffer ) System.out.printf( " %2d

Libera o bloqueio (4 de 5)

", value ); // gera a sada dos valores no buffer

2005 by Pearson Education do Brasil

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119

System.out.print( "\n " ); for ( int i = 0; i < buffer.length; i++ ) System.out.print( "---- " ); System.out.print( "\n { if ( i == writeIndex && i == readIndex ) System.out.print( " WR" ); // ndice de gravao e de leitura else if ( i == writeIndex ) System.out.print( " W " ); // s ndice de gravao else if ( i == readIndex ) System.out.print( " R " ); // s ndice de leitura else System.out.print( " " ); // nenhum dos ndices } // fim do for " );

62

Resumo
CircularBuffer .java

for ( int i = 0; i < buffer.length; i++ )

(5 de 5)

120 121 System.out.println( "\n" ); 122 } // fim do mtodo displayState 123 } // fim da classe CircularBuffer

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

// Fig 23.14: CircularBufferTest.java // Aplicativo mostra duas threads que manipulam um buffer circular. import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CircularBufferTest { public static void main( String[] args ) {

63

Resumo
CircularBufferTest .java

// cria novo pool de threads com duas threads Cria CircularBuffer ExecutorService application = Executors.newFixedThreadPool( 2 ); // cria CircularBuffer para armazenar ints Buffer sharedLocation = new CircularBuffer(); try // tenta iniciar a produtora e a consumidora { application.execute( new Producer( sharedLocation ) ); application.execute( new Consumer( sharedLocation ) ); } // fim do try catch ( Exception exception ) { exception.printStackTrace(); } // fim do catch application.shutdown(); } // fim do main

(1 de 4) para uso tanto pelo produtor como pelo consumidor

Executa o produtor e o consumidor em threads separadas

28 } // fim da classe CircularBufferTest

2005 by Pearson Education do Brasil

Producer writes 1 (buffers occupied: 1) buffers: 1 -1 -1 ---- ---- ---R W Consumer reads 1 (buffers occupied: 0) buffers: 1 -1 -1 ---- ---- ---WR All buffers empty. Consumer waits. Producer writes 2 (buffers occupied: 1) buffers: 1 2 -1 ---- ---- ---R W Consumer reads 2 (buffers occupied: 0) buffers: 1 2 -1 ---- ---- ---WR Producer writes 3 (buffers occupied: 1) buffers: 1 2 3 ---- ---- ---W R Consumer reads 3 (buffers occupied: 0) buffers: 1 2 3 ---- ---- ---WR Producer writes 4 (buffers occupied: 1) buffers: 4 2 3 ---- ---- ---R W

64

Resumo
CircularBufferTest .java

(2 de 4)

2005 by Pearson Education do Brasil

Producer writes 5 (buffers occupied: 2) buffers: 4 5 3 ---- ---- ---R W Consumer reads 4 (buffers occupied: 1) buffers: 4 5 3 ---- ---- ---R W Producer writes 6 (buffers occupied: 2) buffers: 4 5 6 ---- ---- ---W R Producer writes 7 (buffers occupied: 3) buffers: 7 5 6 ---- ---- ---WR Consumer reads 5 (buffers occupied: 2) buffers: 7 5 6 ---- ---- ---W R Producer writes 8 (buffers occupied: 3) buffers: 7 8 6 ---- ---- ---WR

65

Resumo
CircularBufferTest .java

(3 de 4)

2005 by Pearson Education do Brasil

Consumer reads 6 (buffers occupied: 2) buffers: 7 8 6 ---- ---- ---R W Consumer reads 7 (buffers occupied: 1) buffers: 7 8 6 ---- ---- ---R W Producer writes 9 (buffers occupied: 2) buffers: 7 8 9 ---- ---- ---W R Consumer reads 8 (buffers occupied: 1) buffers: 7 8 9 ---- ---- ---W R Consumer reads 9 (buffers occupied: 0) buffers: 7 8 9 ---- ---- ---WR Producer writes 10 (buffers occupied: 1) buffers: 10 8 9 ---- ---- ---R W Producer done producing. Terminating Producer. Consumer reads 10 (buffers occupied: 0) buffers: 10 8 9 ---- ---- ---WR Consumer read values totaling: 55. Terminating Consumer.

66

Resumo
CircularBufferTest .java

(4 de 4)

2005 by Pearson Education do Brasil

23.9 Relacionamento produtor/ consumidor: ArrayBlockingQueue


ArrayBlockingQueue.
Verso completamente implementada do buffer circular. Implementa a interface BlockingQueue.
Declara os mtodos put e take para gravar dados no buffer e ler dados do buffer, respectivamente.

67

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

// Fig. 23.15: BlockingBuffer.java // Classe sincroniza acesso a um buffer de bloqueio. import java.util.concurrent.ArrayBlockingQueue; public class BlockingBuffer implements Buffer { private ArrayBlockingQueue<Integer> buffer; public BlockingBuffer() { buffer = new ArrayBlockingQueue<Integer>( 3 ); } // fim do construtor BlockingBuffer // coloca o valor no buffer public void set( int value ) { try { buffer.put( value ); // coloca o valor no buffer circular System.out.printf( "%s%2d\t%s%d\n", "Producer writes ", value, "Buffers occupied: ", buffer.size() ); } // fim do try catch ( Exception exception ) { exception.printStackTrace(); } // fim do catch } // fim do mtodo set

68

Resumo
BlockingBuffer .java

(1 de 2) Cria uma instncia de ArrayBlockingQueue para armazenar dados

Coloca um valor no buffer; bloqueia se o buffer estiver cheio

2005 by Pearson Education do Brasil

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

// retorna valor do buffer public int get() { int readValue = 0; // inicializa de valor lido a partir do buffer try { readValue = buffer.take(); // remove valor do buffer circular System.out.printf( "%s %2d\t%s%d\n", "Consumer reads ", readValue, "Buffers occupied: ", buffer.size() ); } // fim do try catch ( Exception exception ) { exception.printStackTrace(); } // fim do catch return readValue; } // fim do mtodo get

69

Resumo
BlockingBuffer .java

(2 de 2) Remove o valor do buffer; bloqueia se o buffer estiver vazio

47 } // fim da classe BlockingBuffer

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

// Fig 23.16: BlockingBufferTest.java // Aplicativo mostra duas threads que manipulam um buffer de bloqueio. import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class BlockingBufferTest { public static void main( String[] args ) {

70

Resumo
BlockingBufferTest .java

// cria novo pool de thread com duas threads Cria um BlockingBuffer ExecutorService application = Executors.newFixedThreadPool( 2 ); // cria BlockingBuffer para armazenar ints Buffer sharedLocation = new BlockingBuffer(); try // tenta iniciar produra e consumidora {

(1 de 2) para uso no produtor e consumidor

Executa o produtor e o consumidor em threads separadas

application.execute( new Producer( sharedLocation ) ); application.execute( new Consumer( sharedLocation ) ); } // fim do try catch ( Exception exception ) { exception.printStackTrace(); } // fim do catch

2005 by Pearson Education do Brasil

26 27

application.shutdown(); } // fim do main

71

28 } // fim da classe BlockingBufferTest Producer Consumer Producer Consumer Producer Consumer Producer Consumer Producer Consumer Producer Consumer Producer Producer Consumer Producer Consumer Producer writes 1 reads 1 writes 2 reads 2 writes 3 reads 3 writes 4 reads 4 writes 5 reads 5 writes 6 reads 6 writes 7 writes 8 reads 7 writes 9 reads 8 writes 10 Buffers Buffers Buffers Buffers Buffers Buffers Buffers Buffers Buffers Buffers Buffers Buffers Buffers Buffers Buffers Buffers Buffers Buffers occupied: occupied: occupied: occupied: occupied: occupied: occupied: occupied: occupied: occupied: occupied: occupied: occupied: occupied: occupied: occupied: occupied: occupied: 1 0 1 0 1 0 1 0 1 0 1 0 1 2 1 2 1 2

Resumo
BlockingBufferTest .java

(2 de 2)

Producer done producing. Terminating Producer. Consumer reads 9 Buffers occupied: 1 Consumer reads 10 Buffers occupied: 0 Consumer read values totaling 55. Terminating Consumer.

2005 by Pearson Education do Brasil

72

23.10 Multithreading com GUI


Componentes GUI Swing:
No so seguros para threads.
As atualizaes devem ser realizadas no caso de uma thread de despacho de evento.
Utiliza o mtodo static invokeLater da classe SwingUtilities e passa para ele um objeto Runnable.

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10

// Fig. 23.17: RunnableObject.java // Runnable que grava um caractere aleatrio em um JLabel import java.util.Random; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import javax.swing.JLabel; import javax.swing.SwingUtilities; import java.awt.Color; public class RunnableObject implements Runnable private private private private

73

Resumo
.java

RunnableObject Implementa a interface Runnable

11 { 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

static Random generator = new Random(); // para letras aleatrias Lock lockObject; // bloqueio de aplicativo; passado para o construtor Varivel Condition para Condition suspend; // usado para suspender e retomar thread suspender as threads boolean suspended = false; // true se a thread for suspensa

(1 de 4) Lock (bloqueia) para implementar excluso mtua

private JLabel output; // JLabel para sada

public RunnableObject( Lock theLock, JLabel label ) { lockObject = theLock; // armazena o Lock para o aplicativo suspend = lockObject.newCondition(); // cria nova Condition output = label; // armazena JLabel para gerar sada de caractere Cria um Lock } // fim do construtor RunnableObject // coloca os caracteres aleatrios na GUI public void run() {

Boolean para controlar se a thread foi suspensa

e uma varivel Condition

Obtm o nome da thread atual


// obtm nome de thread em execuo final String threadName = Thread.currentThread().getName();

2005 by Pearson Education do Brasil

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

while ( true ) // infinito; ser terminado de fora { try { // dorme por at 1 segundo Thread.sleep( generator.nextInt( 1000 ) ); lockObject.lock(); // obtm o bloqueio try { while ( suspended ) faz loop at no ser { } // fim do while } // fim do try finally { lockObject.unlock(); // desbloqueia o bloqueio } // fim do finally } // fim do try

74

Resumo
Obtm o bloqueio para impor a excluso mtua RunnableObject
.java

(2 de 4) suspenso Espera enquanto a thread suspensa

suspend.await(); // suspende a execuo do thread

Libera o bloqueio

// se a thread interrompida durante espera/enquanto dormia catch ( InterruptedException exception ) { exception.printStackTrace(); // imprime o rastreamento de pilha } // fim do catch

2005 by Pearson Education do Brasil

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

// exibe o caractere no JLabel correspondente SwingUtilities.invokeLater( new Runnable() {

75

Chama invokeLater

Resumo

// seleciona o caractere aleatrio e o exibe Uma Runnable passada para o public void run() RunnableObject mtodo invokeLater { .java // seleciona a letra maiscula aleatria char displayChar = (3 de 4) ( char ) ( generator.nextInt( 26 ) + 65 ); // gera sada de caractere em JLabel output.setText( threadName + ": " + displayChar ); } // fim do mtodo run } // fim da classe interna ); // fim da chamada para SwingUtilities.invokeLater } // fim do while } // fim do mtodo run

2005 by Pearson Education do Brasil

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93

// altera o estado suspenso/em execuo public void toggle() { suspended = !suspended; // alterna booleano que controla estado // muda cor de rtulo na suspenso/retomada output.setBackground( suspended ? Color.RED : Color.GREEN ); lockObject.lock(); // obtm o bloqueio try { if ( !suspended ) // se a thread foi retomada { suspend.signal(); // libera o bloqueio } // fim do if } // fim do try finally {

76

Resumo
RunnableObject .java

(4 de 4) Obtm o bloqueio para a aplicao

Retoma uma thread em espera

94 lockObject.unlock(); // libera o bloqueio 95 } // fim do finally 96 } // fim do mtodo toggle 97 } // fim da classe RunnableObject

Libera o bloqueio

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

// Fig. 23.18: RandomCharacters.java // A classe RandomCharacters demonstra a interface Runnable import java.awt.Color; import java.awt.GridLayout; import java.awt.event.ActionEvent; import import import import import import import import import java.awt.event.ActionListener; java.util.concurrent.Executors; java.util.concurrent.ExecutorService; java.util.concurrent.locks.Condition; java.util.concurrent.locks.Lock; java.util.concurrent.locks.ReentrantLock; javax.swing.JCheckBox; javax.swing.JFrame; javax.swing.JLabel;

77

Resumo
RandomCharacters .java

(1 de 4)

16 public class RandomCharacters extends JFrame implements ActionListener 17 { Cria um Lock 18 19 20 21 22 23 24 25

para a aplicao

private final static int SIZE = 3; // nmero de threads private JCheckBox checkboxes[]; // array de JCheckBoxes private Lock lockObject = new ReentrantLock( true ); // nico bloqueio // array de RunnableObjects para exibir caracteres aleatrios private RunnableObject[] randomCharacters = new RunnableObject[ SIZE ];

2005 by Pearson Education do Brasil

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

// configura GUI e arrays public RandomCharacters() { checkboxes = new JCheckBox[ SIZE ]; // aloca espao para array setLayout( new GridLayout( SIZE, 2, 5, 5 ) ); // configura o layout // cria novo pool de threads com threads SIZE ExecutorService runner = Executors.newFixedThreadPool( SIZE ); // loop itera SIZE vezes

78

Resumo
RandomCharacters .java

for ( int count = 0; count < SIZE; count++ ) { JLabel outputJLabel = new JLabel(); // cria JLabel outputJLabel.setBackground( Color.GREEN ); // configura cor

(2 de 4) Cria um pool de threads para as threads em execuo

outputJLabel.setOpaque( true ); // configura JLabel para ser opaco add( outputJLabel ); // adiciona JLabel ao JFrame // cria JCheckBox para controlar suspender/retomar o estado checkboxes[ count ] = new JCheckBox( "Suspended" ); // adiciona o ouvinte que executa quando JCheckBox clicada checkboxes[ count ].addActionListener( this ); add( checkboxes[ count ] ); // adiciona JCheckBox ao JFrame

2005 by Pearson Education do Brasil

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

// cria um novo RunnableObject randomCharacters[ count ] = new RunnableObject( lockObject, outputJLabel ); // executa RunnableObject runner.execute( randomCharacters[ count ] ); } // fim do for setSize( 275, 90 ); // configura o tamanho da janela setVisible( true ); // configura a janela runner.shutdown(); // desliga quando as threads terminam } // fim do construtor RandomCharacters // trata eventos da JCheckBox public void actionPerformed( ActionEvent event ) {

79

Resumo
Executa uma Runnable
RandomCharacters .java

(3 de 4)

Desativa o pool de threads quando as threads concluem suas tarefas

// faz loop sobre todas as JCheckBoxes no array for ( int count = 0; count < checkboxes.length; count++ ) { // verifica se essa JCheckBox foi a origem do evento if ( event.getSource() == checkboxes[ count ] ) randomCharacters[ count ].toggle(); // alterna o estado } // fim do for } // fim do mtodo actionPerformed

2005 by Pearson Education do Brasil

76 77 78 79 80 81 82 83

public static void main( String args[] ) { // cria novo objeto RandomCharacters RandomCharacters application = new RandomCharacters(); // configura aplicativo para terminar quando a janela fechada application.setDefaultCloseOperation( EXIT_ON_CLOSE ); } // fim do main

80

Resumo
RandomCharacters .java

84 } // fim da classe RandomCharacters

(4 de 4)

2005 by Pearson Education do Brasil

23.11 Outras classes e interfaces em java.util.concurrent


Interface Callable:
Declara o mtodo call. O mtodo call permite que uma tarefa concorrente retorne um valor ou lance uma exceo. O mtodo Executorservice submit recebe uma Callable e retorna uma Future que representa o resultado da tarefa.

81

Interface Future:
Declara o mtodo get. O mtodo get retorna o resultado da tarefa representada pela Future.

2005 by Pearson Education do Brasil

23.12 Monitores e bloqueios de monitor


Monitores:
Cada objeto Java tem um monitor.
Permite que uma thread por vez execute dentro de uma instruo synchronized. Threads que esperam para adquirir o bloqueio de monitor so colocadas no estado bloqueado. O mtodo Object wait coloca uma thread no estado de espera. O mtodo Object notify acorda uma thread em espera. O mtodo Object notifyAll acorda todas as threads em espera.

82

2005 by Pearson Education do Brasil

83

Observao de engenharia de software 23.3


O bloqueio que ocorre com a execuo dos mtodos synchronized poderia levar a um impasse se os bloqueios nunca fossem liberados. Quando ocorrem excees, o mecanismo de exceo do Java coordena com o mecanismo de sincronizao do Java para liberar bloqueios e evitar esses tipos de impasses.

2005 by Pearson Education do Brasil

84

Erro comum de programao 23.5


Ocorre um erro se uma thread emite um wait, um notify ou um notifyAll sobre um objeto sem adquirir um bloqueio para ela. Isso causa uma IllegalMonitorStateException.

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

// Fig. 23.19: SynchronizedBuffer.java // SynchronizedBuffer sincroniza acesso a um nico inteiro compartilhado. public class SynchronizedBuffer implements Buffer { private int buffer = -1; // compartilhado pelos threads producer e consumer private boolean occupied = false; // contagem de buffers ocupados // coloca o valor no buffer public synchronized void set( int value ) { while ( occupied ) { // envia informaes de thread e de buffer para a sada, ento espera try { // enquanto no houver posies vazias, coloca a thread em estado de espera

85

Resumo
SynchronizedBuffer .java

(1 de 3) Declara um mtodo set synchronized

Espera at que o buffer esteja vazio

System.out.println( "Producer tries to write." ); displayState( "Buffer full. Producer waits." ); wait(); } // fim do try catch ( InterruptedException exception ) { exception.printStackTrace(); } // fim do catch } // fim do while buffer = value; // configura novo valor do buffer

Configura o valor do buffer

2005 by Pearson Education do Brasil

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

// indica que a produtora no pode armazenar outro valor // at a consumidora recuperar valor atual de buffer occupied = true; displayState( "Producer writes " + buffer );

86

Resumo
O buffer est agora ocupado
SynchronizedBuffer .java

notify(); // instrui a thread em espera a entrar no estado executvel } // fim do mtodo set; libera bloqueio em SynchronizedBuffer // retorna valor do buffer public synchronized int get() { // enquanto os dados no so lidos, coloca thread em estado de espera Declara o mtodo while ( !occupied ) { // envia informaes de thread e de buffer para a sada, ento espera try { System.out.println( "Consumer tries to read." ); displayState( "Buffer empty. Consumer waits." ); wait(); } // fim do try catch ( InterruptedException exception ) { exception.printStackTrace(); } // fim do catch } // fim do while

(2 de 3) Notifica a thread em espera de que ela agora pode ler um valor


get synchronized

Espera o buffer encher

2005 by Pearson Education do Brasil

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

// indica que a produtora pode armazenar outro valor // porque a consumidora acabou de recuperar o valor do buffer occupied = false; int readValue = buffer; // armazena valor no buffer displayState( "Consumer reads " + readValue );

87

Resumo
SynchronizedBuffer .java

O buffer agora est vazio

notify(); // instrui a thread em espera a entrar no estado executvel return readValue; } // fim do mtodo get; libera bloqueio em

(3 de 3) Notifica a thread de que agora ela SynchronizedBuffer pode gravar no buffer

// exibe a operao atual e o estado de buffer public void displayState( String operation ) { System.out.printf( "%-40s%d\t\t%b\n\n", operation, buffer, occupied );

75 } // fim do mtodo displayState 76 } // fim da classe SynchronizedBuffer

2005 by Pearson Education do Brasil

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

// Fig 23.20: SharedBufferTest2.java // Aplicativo mostra duas threads que manipulam um buffer sincronizado. import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SharedBufferTest2 { public static void main( String[] args ) { // cria novo pool de threads com duas threads

88

Resumo
SharedBufferTest2 .java

(1 de 3) Cria um 2 ); ExecutorService application = Executors.newFixedThreadPool(SynchronizedBuffer para uso no produtor e no // cria SynchronizedBuffer para armazenar ints consumidor
Buffer sharedLocation = new SynchronizedBuffer(); System.out.printf( "%-40s%s\t\t%s\n%-40s%s\n\n", "Operation", "Buffer", "Occupied", "---------", "------\t\t--------" ); try // tenta iniciar a produtora e a consumidora {

Executa o produtor e o consumidor em threads separadas

application.execute( new Producer( sharedLocation ) ); application.execute( new Consumer( sharedLocation ) ); } // fim do try catch ( Exception exception ) { exception.printStackTrace(); } // fim do catch

2005 by Pearson Education do Brasil

29 30

application.shutdown(); } // fim do main

89

31 } // fim da classe SharedBufferTest2 Operation --------Consumer tries to read. Buffer empty. Consumer waits. Producer writes 1 Consumer reads 1 Consumer tries to read. Buffer empty. Consumer waits. Producer writes 2 Consumer reads 2 Producer writes 3 Consumer reads 3 Consumer tries to read. Buffer empty. Consumer waits. Producer writes 4 Consumer reads 4 Consumer tries to read. Buffer empty. Consumer waits. Producer writes 5 Consumer reads 5 Buffer ------1 1 1 1 2 2 3 3 3 4 4 4 5 5 Occupied -------false true false false true false true false false true false false true false

Resumo
SynchronizedBuffer .java

(2 de 3)

2005 by Pearson Education do Brasil

Producer writes 6 Consumer reads 6 Consumer tries to read. Buffer empty. Consumer waits. Producer writes 7 Consumer reads 7 Consumer tries to read. Buffer empty. Consumer waits. Producer writes 8 Consumer reads 8 Producer writes 9 Producer tries to write. Buffer full. Producer waits. Consumer reads 9 Producer writes 10

6 6 6 7 7 7 8 8 9 9 9 10

true false false true false false true false true true false true

90

Resumo
SynchronizedBuffer .java

(3 de 3)

Producer done producing. Terminating Producer. Consumer reads 10

10

false

Consumer read values totaling 55. Terminating Consumer.

2005 by Pearson Education do Brasil