Java - LSI/USP

Propaganda
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
}
Download