330 likes | 443 Views
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
E N D
Sincronização de Threads Professor: Hyggo Almeida
O que vimos na última aula? • Threads • Ciclo de vida • Escalonamento Sincronização de Threads
O que veremos hoje? • Threads • Sincronização Sincronizaçã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!!! Sincronizaçã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 Sincronização de Threads
Sincronização de Threads • Produtor publicclass Producer extends Thread { privateSharedResourceresource; privateintnumber; public Producer(SharedResourcec, intnumber) { resource = c; this.number = number; } publicvoidrun() { for (inti = 0; i < 10; i++) { resource.put(i); try{ sleep((int)(Math.random() * 100)); } catch (InterruptedException e) { } } } } Sincronização de Threads
Sincronização de Threads • Produtor public class Consumer extends Thread { private SharedResource resource; private int number; public Consumer(SharedResource c, int number) { resource = c; this.number = number; } publicvoid run() { int value = 0; for (int i = 0; i < 10; i++) { value = resource.get(); } } } Sincronização de Threads
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? Sincronizaçã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 consumidorperde 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 Sincronizaçã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 Sincronizaçã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 palavrasynchronized 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 de Threads • Sincronização via locking • Bloco “avulso” de código //.. synchronized { //qualquer trecho de código } //.. synchronized (obj){ //qualquer trecho de código } Sincronização de Threads
Sincronização de Threads • Sincronização via locking • Locking reentrante 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 de Threads • Sincronização via wait e notifyAll 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 de Threads • Sincronização via wait e notifyAll 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 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 Sincronizaçã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) Sincronização de Threads
Sincronização de Threads • Vamos implementar o exemplo do produtor/consumidor... Sincronizaçã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 Sincronizaçã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 Lock aLock = new ReentrantLock(); … aLock.lock(); try{ \\… }finally{ aLock.unlock(); } Sincronização de Threads
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 ocorreu Sincronizaçã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. Sincronização de Threads
Sincronização de Threads • Locks explícitos e variáveis condicionais • Exemplo da classe SharedResource import java.util.concurrent.locks.*; public class SharedResource { privateint contents; privateboolean available = false; private Lock aLock = new ReentrantLock(); private Condition condVar = aLock.newCondition(); //… } Sincronização de Threads
Sincronização de Threads • Locks explícitos e variáveis condicionais • Exemplo da classe SharedResource 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
Sincronização de Threads • Locks explícitos e variáveis condicionais • Exemplo da classe SharedResource 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 produzido condVar.signalAll(); } finally { aLock.unlock(); } } } Sincronização de Threads
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 Sincronizaçã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() Sincronizaçã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... 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
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 • Starvationocorre 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 Sincronizaçã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 Sincronização de Threads
O que vimos hoje? • Threads • Sincronização Sincronização de Threads
O que veremos na próxima aula? • Threads • Pool Sincronização de Threads
Dúvidas? ? Sincronização de Threads