Capítulo 6 - Threads Estudo Certificação Java Roteiro O que uma thread executa Estados e prioridades de um thread Controlando (yelding, suspending, sleeping, blocking) Monitor States e Implementações de escalonamento (wait, notify) Lock e sincronização Além do modelo puro e maneiras estranhas de sincronizar Estudo Certificação Java O que uma thread executa (1) Conteúdo do run() Não imediatamente! A invocação do start() registra aquele código a um escalonador de threads e o torna “elegível” para rodar 2 maneiras: extends Thread e implements Runnable Estudo Certificação Java O que uma thread executa (2) public class CounterThread extends Thread{ public void run() { for (int i=0; i<10;i++) { System.out.println(“Counting: “+i); } } } CounterThread ct = new CounterThread(); ct.start(); Estudo Certificação Java O que uma thread executa (3) public class DownCounter implements Runnable{ public void run() { for (int i=10; i>=1;i--) { System.out.println(“Counting down: “+i); } } } DownCounter dc = new DownCounter(); Thread t = new Thread(dc); t.start(); Estudo Certificação Java O que uma thread executa (4) implements vs. extends extends tem o problema de não haver herança múltipla em Java extends é mais simples implements está mais de acordo com a idéia de OO: o fato de uma classe se comportar como uma thread não necessariamente justifica a “força” de dizer que “é uma Thread” voltando do run a Thread está morta: não pode restartar, mas pode invocar seus métodos stop() não existe no 1.2: usar interrupt() Estudo Certificação Java Estados de uma Thread Running Monitor States Suspended Asleep Ready suspend deprecated apenas o escalonador pode mexer numa Estudo Certificação Java Blocked Prioridades de uma Thread Inteiros de 1 a 10. Geralmente escolhe-se entre as waiting threads de maior prioridade Não há garantia de que a que espera há mais tempo será escolhida Default é 5, mas as novas são criadas com a prioridade da Thread que as criou int oldPriority = theThread.getPriority(); int newPriority = Math.min(oldPriority+1,Thread.MAX_PRIORITY); theThread.setPriority(newPriority); Estudo Certificação Java Controlando Threads (1) Yeld: de Running p/ Ready permite que outras Threads que estejam “waiting” seja escalonadas se não houver outras esperando, então continua rodando imediatamente exemplo: rotina pesada faz um yeld periodicamente p/ dar tempo da GUI atuar (botão “interromper” poder ser pressionado) vale a pena diminuir prioridade também, mas não é garantia de funcionar em todas plataformas Estudo Certificação Java Controlando Threads (2) Suspending: não caem na prova Sleeping: mantém dormindo por um período (milisegundos e nanosegundos opcionalmente) tempo expirado ou interrupt -> Ready como yeld é método estático havendo interrupt() sobre ela, joga InterruptedException ao voltar p/ “Running” state Estudo Certificação Java Controlando Threads (3) Blocking: de Running p/ Blocked usada para esperar que alguma condição ocorra: exemplo I/O try { Socket sock = new Socket(“magnesium”, 5505); InputStream istr = sock.getInputStream(); int b = istr.read(); } catch (IOException ex) {} sai desse estado quando a condição é satisfeita, ou quando ocorre interrupt Estudo Certificação Java Monitores wait() e notify() (1) Monitor states são bem diferentes dos demais wait() coloca em espera e notify() (e notifyAll()) de volta a Ready: são implementados em Object só podem ser chamados em código synchronized Podem ser preemptivo ou time-sliced: depende da plataforma Estudo Certificação Java Monitores wait() e notify() (2) class Mailbox { public boolean request; public String message; } public class Consumer extends Thread { private Mailbox myMailbox; public Consumer (Mailbox box) { this.myMailbox = box;} public void run() { while (true) { if (myMailbox.request) { System.out.println(myMailbox.message); myMailbox.request = false; } try {sleep(50);} catch (InterruptedException e) {} } } Estudo Certificação Java Monitores wait() e notify() (3) Nada impede que entre o checar o request e imprimir, outra thread mude a mensagem A escolha do tempo de verificação do “request” é difícil Os recursos compartilháveis tem que estar protegidos (synchronized) Quem verifica “request” deve esperar um tempo razoável e ser notificado de sua Estudo Certificação Java mudança Lock e Sincronização (1) Marca-se código com “synchronized” e a VM faz: um thread que quiser executar tal código tem que obter o lock se lock não estiver disponível, fica no estado de esperando lock quando lock é obtido a thread vai para Ready marca-se método como “synchronized” ou parte de um código Estudo Certificação Java Lock e Sincronização (2) class Mailbox { private boolean request; private String message; public synchronized void storeMessage(String message) { request = true; this.message = message;} public synchronized String retrieveMessage() { request = false; return message; } Mas ainda tem-se o problema dos clientes de como eles vão saber e esperar pelo lock para chamar store e retrieve Estudo Certificação Java Lock e Sincronização (3) Entra em código synchronized Seeking Waiting lock Notify, notifyAll, Running wait escalonado timeout ou interrupt Lock obtido Estudo Certificação Java Ready Lock e Sincronização (4) public synchronized String retrieveMessage() { while (request == false) { try { wait(); } catch (InterruptedException e) {} } request = false; return message; } public synchronized void storeMessage(String message) { this.message = message; request = true; notify(); } Estudo Certificação Java Lock e Sincronização (5) Se um consumidor quiser chamar retrieve num objeto sem mensagem ele entra no waiting state Em algum momento um produtor coloca uma mensagem e por conseguinte muda o request e notifica O consumidor vai para “seeking lock” e quando o obtém imprime uma mensagem consistente Estudo Certificação Java Lock e Sincronização (6) public synchronized String retrieveMessage() { while (request == false) { try { wait(); } catch (InterruptedException e) {} }request = false; notify(); return message; } public synchronized void storeMessage(String message) { while (request == true) { try {wait(); } catch (InterruptedException e) {} } request = true; this.message = message; notify(); } Resolve problema de produtor usar store quando Estudo Certificação Java já há message Resumindo wait e notify Wait. A thread que a chamou: desiste da CPU desiste do lock vai p/ o “pool” de monitores em “waiting” notify: sái do “pool” de monitores em “waiting” e vai p/ o estado de “seeking lock” terá de re-adquirir o lock p/ prosseguir Estudo Certificação Java Além do modelo puro (+ de 1 produtor/consumidor) Usar while ao invés de if p/ continuar esperando no caso do estado não estar ok usar notifyAll ao invés de notify p/ notificar todas as threads public synchronized void mixedUpMethod { while (i< 16 || f > 4.3f || message.equals(“UH-HO”) { try { wait(); } catch (InterruptedException e) {} } // modifica o estado do monitor e… notifyAll(); } Estudo Certificação Java Maneiras estranhas de sincronizar Fazer lock de uma porção do código em relação a um determinado objeto provável objetivo: liberar locks o quanto antes não bloqueando o método inteiro lock também pode ser sobre this class Strange Sync { Rectangle rect = new Rectangle(11, 13, 1100, 1300); void doIt() { int x = 504; int y = x/3; synchronized(rect) { rect.width -= x;rect.heigth -=y; } } Estudo Certificação Java }