sincronização de threads
DESCRIPTION
Sincronização de Threads. Professor: Hyggo Almeida. O que vimos na última aula ?. Threads Ciclo de vida Escalonamento. O que veremos hoje ?. Threads Sincronização. Sincronização de Threads. As threads vistas até agora são executadas paralelamente Mas não há recursos compartilhados - PowerPoint PPT PresentationTRANSCRIPT
Sincronização de ThreadsProfessor: Hyggo Almeida
Laboratório de Sistemas Embarcados e
Computação PervasivaCentro de Engenharia Elétrica e Informática
Universidade Federal de Campina Grande
O que vimos na última aula?Threads
Ciclo de vida Escalonamento
2Sincronização de Threads
O que veremos hoje?Threads
Sincronização
3Sincronização de Threads
Sincronização de Threads
As threads vistas até agora são executadas paralelamente Mas não há recursos compartilhados Elas são independentes Não se concorre por recursos... ...não há concorrência!!!
4Sincronização de Threads
Sincronização de Threads
Produtor/Consumidor Um produtor gera um número entre 0 e 9 e o
armazena em uma instância de SharedResource O produtor dorme durante um intervalo aleatório
de 0 a 100 ms antes de gerar mais números O consumidor consome os números inteiros
acessando a mesma instância de SharedResource
5Sincronização de Threads
Sincronização de Threads
Produtor
6Sincronização de Threads
public class Producer extends Thread { private SharedResource resource; private int number;
public Producer(SharedResource c, int number) { resource = c; this.number = number; }
public void run() { for (int i = 0; i < 10; i++) { resource.put(i); try { sleep((int)(Math.random() * 100)); } catch (InterruptedException e) { } } }}
Sincronização de Threads
Produtor
7Sincronização de Threads
public class Consumer extends Thread { private SharedResource resource; private int number;
public Consumer(SharedResource c, int number) { resource = c; this.number = number; }
public void run() { int value = 0; for (int i = 0; i < 10; i++) { value = resource.get(); } }}
Sincronização de Threads
Produtor/Consumidor O produtor e o consumidor compartilham dados
da instância de SharedResource O consumidor deve receber um dado número
apenas uma vez... ... mas quem está controlando isso?
8Sincronização de Threads
Sincronização de Threads
Produtor/Consumidor Uma vez que não há sincronização na execução
das threads, pode-se ter duas situações indesejadas: O consumidor perde um número... caso o
produtor produza mais rápido um novo número antes que seja consumido...
O consumidor consome números repetidos... caso o produtor não produza um novo número a tempo
Esse tipo de problema é denominado condição de corrida 9Sincronização de Threads
Sincronização de Threads
Condição de corrida Quando duas ou mais threads ou processos
compartilham dados e o resultado final depende do escalonamento
As atividades do produtor e do consumidor devem ser sincronizadas em dois passos... Travando o objeto (locking), impedindo que duas threads o
acessem ao simultaneamente Fazer com que cada thread coordene seu trabalho,
notificando a outra thread quando o número foi produzido e consumido
10Sincronização de Threads
Sincronização de Threads
Sincronização via locking Trechos do código que possuem estruturas de dados
acessadas por threads diferentes e concorrentes são chamados regiões ou seções críticas
Uma região crítica é demarcada pela palavra synchronized
11Sincronização de Threads
public class SharedResource { private int contents; private boolean available = false;
public synchronized int get() { ... }
public synchronized void put(int value) { ... }}
Sincronização de Threads
Sincronização via locking Bloco “avulso” de código
12Sincronização de Threads
//..synchronized {
//qualquer trecho de código}
//..synchronized (obj){
//qualquer trecho de código}
Sincronização de Threads
Sincronização via locking Locking reentrante
13Sincronização de Threads
public class Reentrant { public synchronized void a() { b(); System.out.println(“Estou em a()”); }
public synchronized void b() { System.out.println(“Estou em b()”); }}
Sincronização de Threads
Sincronização via wait e notifyAll
14Sincronização de Threads
public synchronized int get() { while (available == false) { try { //esperar o produtor avisar que produziu wait(); } catch (InterruptedException e) { } } available = false; //notificar produtor de que o valor foi recuperado notifyAll(); return contents;}
Sincronização de Threads
Sincronização via wait e notifyAll
15Sincronização de Threads
public synchronized void put(int value) { while (available == true) { try { //Esperar aviso do consumidor de que recuperou número wait(); } catch (InterruptedException e) { } } contents = value; available = true; //Notificar consumidor de que número foi produzido notifyAll();}
Sincronização de Threads
Sincronização via wait e notifyAll O método wait libera o lock e espera
notificação para continuar Para que outra thread possa adquirir o lock, fazer
seu trabalho e então “acordar” a original (com notifyAll)
Ao acordar, tem-se o lock novamente
O método notifyAll “acorda” todas as threads que estão em wait (nesse objeto) As threads que acordam competem pelo lock Quando uma thread tem o lock, as outras dormem
16Sincronização de Threads
Sincronização de Threads
Sincronização via wait e notifyAll Há também o método notify (escolha
arbitrária) Só se pode usar wait(), notify() e notifyAll()
quando se está de posse do lock do objeto (dentro de um bloco synchronized)
wait() espera uma condição para o objeto corrente e esta condição ocorre com notify() no mesmo objeto wait() wait(milisegundos) wait(milisegundos, nanosegundos)
17Sincronização de Threads
Sincronização de Threads
Vamos implementar o exemplo do produtor/consumidor...
18Sincronização de Threads
Sincronização de Threads
Locks explícitos e variáveis condicionais Pode-se proteger regiões críticas com locks
explícitos Permite proteger alguns statements Permite proteger múltiplos métodos
Para criar um lock explícito, instancia-se uma implementação da interface Lock Em geral, ReentrantLock
19Sincronização de Threads
Sincronização de Threads
Locks explícitos e variáveis condicionais Para obter o lock, utiliza-se o método lock() Para liberar... unlock() Uma vez que o lock não é liberado
automaticamente, deve-se usar try...finally para garantir sua liberação
20Sincronização de Threads
Lock aLock = new ReentrantLock();…aLock.lock();try{\\…}finally{ aLock.unlock();}
Sincronização de Threads
Locks explícitos e variáveis condicionais Para esperar por um lock explícito, cria-se uma
variável condicional Um objeto que implementa a interface Condition
Usar Lock.newCondition() para criar uma condição
A condição provê métodos: await() para esperar até a condição ser
verdadeira signal() e signalAll() para avisar os
threads que a condição ocorreu21Sincronização de Threads
Sincronização de Threads
Locks explícitos e variáveis condicionais Variações de await()
await () - Espera uma condição ocorrer. awaitUninterruptibly() - Espera uma condição ocorrer. Não pode ser
interrompido. awaitNanos(long timeout) - Espera uma condição ocorrer. Espera
no máximo timeout nanossegundos. await(long timeout, TimeUnit unit) - Espera uma condição ocorrer.
Espera no máximo timeout TimeUnit. await(Date timeout) - Espera uma condição ocorrer. Espera no
máximo até a data especificada.
22Sincronização de Threads
Sincronização de Threads
Locks explícitos e variáveis condicionais Exemplo da classe SharedResource
23Sincronização de Threads
import java.util.concurrent.locks.*;public class SharedResource { private int contents; private boolean available = false; private Lock aLock = new ReentrantLock(); private Condition condVar = aLock.newCondition(); //…}
Sincronização de Threads
Locks explícitos e variáveis condicionais Exemplo da classe SharedResource
24Sincronização de Threads
public int get() { aLock.lock(); try { while (available == false) { try {
condVar.await(); //Esperar aviso de produção} catch (InterruptedException e) { }
} available = false;
//Notificar produtor de que número foi consumido condVar.signalAll(); } finally { aLock.unlock(); return contents; } }
Sincronização de Threads
Locks explícitos e variáveis condicionais Exemplo da classe SharedResource
25Sincronização de Threads
public void put(int value) { aLock.lock(); try { while (available == true) { try {condVar.await();//Esperar aviso de que foi consumido
} catch (InterruptedException e) { } } contents = value; available = true;
//Notificar consumidor de que número foi produzidocondVar.signalAll();
} finally { aLock.unlock(); } }}
Sincronização de Threads
Estruturas de dados sincronizadas Em vez de construir estruturas sincronizadas
como o SharedObject, pode-se utilizar algumas pré-definidas Classes do pacote java.util.concurrent Exemplo: BlockingQueue
Fila que trata de todos os detalhes de sincronização
26Sincronização de Threads
Sincronização de Threads
Sincronizando coleções As coleções de Java em geral (ArrayList, ...) não
são sincronizadas (não são thread-safe) Exceção é Vector
Para criar coleções sincronizadas, deve-se criar um decorador da coleção que sincroniza os métodos Java já fornece tais decoradores na classe Collections
Collections.synchronizedCollection() Collections.synchronizedList() Collections.synchronizedMap() Collections.synchronizedSet() Collections.synchronizedSortedMap() Collections.synchronizedSortedSet()
27Sincronização de Threads
Sincronização de Threads
Sincronizando coleções Apenas a lista decorada deve ser usada a partir
de então...
Iterações devem ser sincronizadas...
28Sincronização de Threads
List list = Collections.synchronizedList(new ArrayList());
synchronized(list) { Iterator i = list.iterator(); // Deve estar dentro do bloco while (i.hasNext()) foo(i.next());}
Sincronização de Threads
Starvation e deadlock... Várias threads competem por recursos...
Equidade (fairness) existe quando cada thread recebe recursos suficientes para progredir
Um sistema com equidade deve evitar starvation e deadlock Starvation ocorre quando uma ou mais
threads não conseguem obter recursos para progredir
Deadlock é uma starvation que ocorre quando as threads esperam por uma condição que nunca vai ocorrer
29Sincronização de Threads
Sincronização de Threads
Starvation e deadlock... Exemplo clássico: filósofos!
Cinco filósofos estão sentados numa mesa redonda Na frente de cada filósofo, há uma tijela de arroz Entre cada dois filósofos há um pauzinho chinês Para poder comer um bocado de arroz, um filósofo
deve ter 2 pauzinhos: o da esquerda e da direita Os filósofos devem achar uma forma de
compartilhar pauzinhos de forma a que todos possam comer
Applet: http://dsc.ufcg.edu.br/~jacques/cursos/map/html/threads/sincronizacao.html
30Sincronização de Threads
O que vimos hoje?Threads
Sincronização
31Sincronização de Threads
O que veremos na próxima aula?
Threads Pool
32Sincronização de Threads
Dúvidas?
?33Sincronização de Threads