Академический Документы
Профессиональный Документы
Культура Документы
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
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
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.
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.
Estado terminado:
Uma thread executvel entra nesse estado quando completa sua tarefa.
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.
11
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).
13
14
15
16
17
Interface Executor:
Declara o mtodo execute. Cria e gerencia um grupo de threads chamado pool de threads.
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.
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
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)
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)
27 28
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
23
Interface Lock:
O mtodo lock obtm o bloqueio, impondo a excluso mtua. O mtodo unlock libera o bloqueio.
24
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.
26
27
28
29
30
31
32
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
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
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
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
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)
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
L o valor do buffer
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)
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)
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
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.
43
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
(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
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
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;
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
(3 de 5)
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
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
Resumo
SynchronizedBuffer .java
(5 de 5)
Libera o bloqueio sobre os dados compartilhados
49
50
51
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)
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
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
(3 de 4)
2 2 3 3 4 4
4 5 5
false
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
55
Resumo
SharedBufferTest2 .java
(4 de 4)
10
false
56
57
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
Variveis de condio (1 de 5) para controlar a gravao e leitura Buffer circular; fornece trs espaos para dados
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
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
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)
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
(5 de 5)
120 121 System.out.println( "\n" ); 122 } // fim do mtodo displayState 123 } // fim da classe CircularBuffer
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
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)
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)
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)
67
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
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
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 {
application.execute( new Producer( sharedLocation ) ); application.execute( new Consumer( sharedLocation ) ); } // fim do try catch ( Exception exception ) { exception.printStackTrace(); } // fim do catch
26 27
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.
72
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
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
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() {
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
Libera o bloqueio
// se a thread interrompida durante espera/enquanto dormia catch ( InterruptedException exception ) { exception.printStackTrace(); // imprime o rastreamento de pilha } // fim do catch
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
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
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
94 lockObject.unlock(); // libera o bloqueio 95 } // fim do finally 96 } // fim do mtodo toggle 97 } // fim da classe RunnableObject
Libera o bloqueio
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)
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 ];
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
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
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)
// 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
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
(4 de 4)
81
Interface Future:
Declara o mtodo get. O mtodo get retorna o resultado da tarefa representada pela Future.
82
83
84
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
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
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
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
notify(); // instrui a thread em espera a entrar no estado executvel return readValue; } // fim do mtodo get; libera bloqueio em
// 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 );
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 {
application.execute( new Producer( sharedLocation ) ); application.execute( new Consumer( sharedLocation ) ); } // fim do try catch ( Exception exception ) { exception.printStackTrace(); } // fim do catch
29 30
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)
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)
10
false