Você está na página 1de 71

Multithreading ou Execuo Concorrente

Vida real: processos ocorrem simultaneamente (respiramos, pensamos, comemos, corao bate, andamos, o sangue circula...) Computadores:
Executam processos concorrentes; At agora s sabemos programar sequencialmente

Multithreading ou Execuo Concorrente


Linguagens de programao com suporte multiprocessamento:
ADA (governo USA) CHILL (sistemas de telefonia) C/C++ (com bibliotecas de apoio) Java ()

Multithreading ou Execuo Concorrente


Multithreading em Java
Usos: comunicao via rede, comunicao entre processos, problemas tipo produtor-consumidor Difcil: no h metodologia simples de modelar problemas de concorrncia. API j implementada em Java. Gerencia a concorrncia para o programador (oba!) Vrios objetos prontos Devemos usar o que est pronto sempre que possvel!

Threads - Conceitos Bsicos


O que uma thread? Fluxo seqencial de controle dentro de um processo. Conjunto de todos os estados necessrios para um processamento. O suporte a mltiplas linhas de execuo permite que mltiplos processamentos ocorram em "paralelo" (em computadores com um processador, os threads no so executados em paraleloconcorrentemente).

Threads - Conceitos Bsicos


Queremos escrever programas que possam fazer vrias tarefas simultaneamente.
baixar uma imagem pela rede. requisitar um relatrio atualizado do estoque. rodar vrias animaes. tudo ao mesmo tempo.

Cada thread representa a execuo de uma sequncia de comandos independentes.

Estados de uma Thread

Threads - Conceitos Bsicos


Vrias threads em vrias CPUs
Tarefa 1 Tarefa 2

Tarefa 3

Vrias threads compartilhando uma nica CPU

Tarefa 1 Tarefa 2 Tarefa 3

Threads - Conceitos Bsicos

Threads em Java
Suporte a multithreading faz parte da linguagem.
Todo programa executado em pelo menos uma thread.
class UmaUnicaThread { public static void main(String[] args) { // main() executado em um nica thread System.out.println(Thread.currentThread()); for (int i=0; i<30; i++) System.out.println("i == " + i); } }

Exemplo
Thread[main,5,main] i == 0 i == 1 i == 2 i == 3 i == 4 i == 5 i == 6 i == 10 i == 20 i == 11 i == 21 i == 12 i == 22 ... i == 29

Exemplo
class CountThread extends Thread O mtodo run( ) como { int from, to; se fosse um main( ), public CountThread(int from, int to) s que no esttico { this.from = from; this.to = to; } public void run() { for (int i=from; i<to; i++) System.out.println("i == " + i); } public static void main(String[] args) { // Dispara 5 threads, cada uma ir contar 10 vezes for (int i=0; i<5; i++) { CountThread t = new CountThread(i*10, (i+1)*10); t.start(); } } }

Exemplo
class CountThread extends Thread { int from, to; public CountThread(int from, int to) { this.from = from; this.to = to; } public void run() Iniciar uma thread ir criar { for (int i=from; i<to; i++) uma nova sequncia de System.out.println("i == " + i); controle e chamar o mtodo } run( ) da thread public static void main(String[] args) { // Dispara 5 threads, cada uma ir contar 10 vezes for (int i=0; i<5; i++) { CountThread t = new CountThread(i*10, (i+1)*10); t.start(); } } }

Exemplo
class CountThread extends Thread Thread uma { int from, to; classe em Java! public CountThread(int from, int to) { this.from = from; this.to = to; } public void run() { for (int i=from; i<to; i++) System.out.println("i == " + i); } public static void main(String[] args) { // Dispara 5 threads, cada uma ir contar 10 vezes for (int i=0; i<5; i++) { CountThread t = new CountThread(i*10, (i+1)*10); t.start(); } } }

Exemplo
main
0..9 10..19 20.29 30..39 40..49

Exemplo
1a. Execuo i == 0 i == 1 i == 2 i == 3 i == 4 i == 5 i == 6 i == 10 i == 20 i == 11 i == 21 i == 12 i == 22 ... 2a. Execuo i == 0 i == 1 i == 2 i == 3 i == 4 i == 10 i == 20 i == 11 i == 21 i == 31 i == 41 i == 5 i == 6 ...

Threads API
Thread()
Classe Thread possibilita a criao de um objeto executvel.

void run()
invocado pelo sistema de execuo da JVM. deve-se sobrescrever este mtodo (polimorfismo por sobreposio) para prover o cdigo a ser executado pela thread.

void start()
inicia a thread e provoca a chamada de run().

void stop()
pra a execuo da thread.

void suspend()
suspende a execuo da thread.

void resume()
retoma a execuo interrompida por um suspend().

Threads API
static void sleep(long millis) throws InterruptedException
pe a thread para dormir por um tempo em milisegundos.

void interrupt()
interrompe a thread em execuo.

static boolean interrupted()


testa se a thread foi interrompida.

Threads API
boolean isAlive()
testa se a thread est rodando.

void setPriority(int p)
define a prioridade de execuo da thread.

void yield()
indica ao gerenciador de threads que esta uma boa hora para rodar outras threads.

void join()
espera que uma thread termine sua execuo.

Estados

Estados
Uma thread finalizada:
atravs dos mtodos stop() ou destroy(). ao terminar a execuo do mtodo run().
algumas threads podem continuar rodando mesmo aps a finalizao do run().

se estiver associada a outra thread, terminar juntamente com ela. minhaThread.setDeamon(true).

Threads de Usurio x Deamons


Uma thread do tipo deamon roda sempre como um pano de fundo da thread que a criou.
uma thread deamon termina quando a thread que a criou tambm terminar.

Uma thread que no uma deamon chamada de thread de usurio. Em Java, um programa permanece em execuo enquanto ele possuir pelo menos uma thread no daemon executando. Quando s existem threads do tipo daemon rodando, o programa finalizado.

Threads de Usurio x Deamons


...main(...)... thread1.setDeamon(true); thread1.start(); thread2.setDeamon(true); thread2.start(); thread3.start(); return; Sero automaticamente finalizadas quando o mtodo main( ) for finalizado

Pode continuar a execuo mesmo aps o final de main( )

Uma Classe Executvel


Geralmente no conveniente criar uma subclasse de Thread.
tambm no ser possvel devido ao mecanismo de herana implementado em Java.

A interface Runnable adiciona o mtodo run() sem herdar nada de Thread. (Melhor!)
public interface Runnable { public void run(); }

Exemplo
/* Programa Java que dispara threads */ class CountThreadRun implements Runnable { int from, to; public CountThread(int from, int to) { this.from = from; this.to = to; } public void run() { for (int i=from; i<to; i++) System.out.println("i == " + i); } }

Exemplo
Para executar como uma thread:
// Cria uma instncia de Runnable Runnable r = new CountThreadRun(10,20); // Cria uma instncia de Thread Thread t = new Thread(r); // inicia a execuo da thread t.start();

Exemplo - MultiplaImpressao
/* Este programa cria uma classe chamada MultiplaImpressao*/ public class MultiplaImpressaoThread implements Runnable { Thread threadDaClasse; String string; int contador; int tempoDormindo; /* mtodo construtor da classe */ public MultiplaImpressaoThread (String s, int quantasVezes, int dormir) { contador = quantasVezes; string = s; tempoDormindo = dormir; threadDaClasse = new Thread (this); threadDaClasse.start(); } /*Fim do metodo construtor

Exemplo - MultiplaImpressao
public void run () {
while (contador > 0) { System.out.println (string); try { Thread.sleep (tempoDormindo); } catch (Exception e) { } } /*fim-while */

} /* Fim do metodo run */ public static void main (String args[]) {


new MultiplaImpressaoThread (ping", 5, 300); new MultiplaImpressaoThread (pong", 5, 500);

} /* Fim do metodo main */ } /* Fim da classe MultiplaImpressaoThread */

Exemplo (2)
class MeuApplet extends Applet implements Runnable { private Thread timer = null; public void init() { timer = new Thread(this); timer.start(); } ... public void run() { ... } }

Exemplo Relogio Digital


import java.awt.Graphics; import java.awt.Font; import java.util.Date; public class RelogioDigitalThreads extends java.applet.Applet implements Runnable { Font aFonte = new Font("TimesRoman",Font.BOLD,24); Date aData; Thread runner; public void start() { if (runner == null) { runner = new Thread(this); runner.start(); } } public void stop() { if (runner != null) { runner.stop(); runner = null; } }

Exemplo Relogio Digital


public void run() { while (true) { aData = new Date(); repaint(); try { Thread.sleep(1000); } catch (InterruptedException e) {} } } public void paint (Graphics g) { g.setFont(aFonte); g.drawString(aData.toString(),10,50); } }

Exemplo Relogio Digital


http://www.cria.org.br/~bene/PA2/Threads/teste.html

Construtores
public public public public public Thread(); Thread(Runnable target); Thread(String name); Thread(Runnable target, String name); Thread(ThreadGroup group, Runnable target); public Thread(ThreadGroup group, String name); public Thread(ThreadGroup group, Runnable target, String name);

Escalonamento em Java
Mecanismo que determina como os threads executveis (runnable) iro utilizar tempo de CPU.
Preemptiva. filas de prioridades. no h diviso de tempo entre as filas (time sliced).

threads com menor prioridade podem ser executadas quando as de maior prioridade no estiverem rodando.
sleep(), yield(), stop()

Prioridade
Cada thread apresenta uma prioridade de execuo.
pode ser alterada com setPriority(int p) pode ser lida com getPriority()

Algumas constantes incluem:


Thread.MIN_PRIORITY Thread.MAX_PRIORITY Thread.NORM_PRIORITY o padro Thread.NORM_PRIORITY

Prioridade
Nem todo sistema operacional tem 10 nveis distintos de prioridade. O Windows, por exemplo, tem apenas 7. Assim, uma thread de prioridade n pode acabar tendo os mesmos privilgios (ou at menos) que outra de prioridade n-1, se ambas as prioridades forem mapeadas para um mesmo valor pela JVM.

Threads Egostas
Uma thread egosta aquela que quando toma conta da mquina, no quer sair nunca mais. Neste caso, s o SO pode retir-la da mquina. No boa prtica de programao fazer threads egostas. Soluo: usar os comandos sleep() e yield().

O mtodo sleep()
O mtodo sleep coloca o processo para dormir por um nmero de milissegundos definido pelo seu parmetro.
public void run() { for(;;) { try { sleep(1000); // Pause for 1 second } catch (InterruptedException e) { return; // caused by thread.interrupt() } System.out.println(Tick); } }

O mtodo sleep()
public void run() { for(;;) { try { sleep(1000); } catch (InterruptedException e) { return; } System.out.println(Tick); } }

Esta thread no necessariamente imprime a palavra Tick uma vez por segundo. Afinal, ela entra em estado idle e no necessariamente escalonada imediatamente aps acordar do seu sono. O tempo do sleep um limite inferior para o tempo entre impresses.

Interrompendo uma thread


Quando o mtodo run() termina, a thread se encerra (entra em estado dead e espera que o Garbage Collector a elimine da memria). Neste caso, est tudo bem. Entretanto, outros podem pedir que a thread termine.

Para faz-lo, devemos usar o mtodo interrupt() da thread.

Interrompendo uma thread


Logo, o cdigo da nosso mtodo run() deveria ter o seguinte formato:
public void run() { : while((!isInterrupted())&&(outras condies) { //faa o trabalho } : }

O mtodo interrupted() esttico enquanto que o isInterrupted() pertence ao objeto e no tem efeitos colaterais. O problema que esta thread uma thread egosta!!!!

Interrompendo o sono de uma Thread


Quando uma thread est em modo sleep e sofre uma interrupo, uma exceo da classe InterruptedException acontece. Logo, devemos trat-la!!! Podemos ignorar o pedido de interrupo, se a thread for importante o suficiente ou podemos preparar-nos para sair. Nota: a interrupo s ocorre se estvamos dormindo. Caso contrrio, temos que checar os flags de interrupo.

Interrompendo o sono de uma Thread


O cdigo para fazer isto :
public void run() { : try { while(condies) { //faa o trabalho : sleep(n) : //mais trabalho } } catch (InterruptedException e) { //A thread foi interrompida durante o sono } finally { //Aes de limpeza e trmino do loop } : }

Sendo bonzinho...
Uma maneira de uma thread ser gentil, usar o mtodo yield(). Usando este mtodo, ela sai do controle da mquina e diz para a JVM escalonar outra thread em seu lugar. O problema que se a thread boazinha a da mais alta prioridade, certas implementaes da JVM pode escalonla novamente. melhor chamar o mtodo sleep(). Assim garantimos que a thread atual no ser escalonada imediatamente...

Esperando uma condio


Imagine que voc deseja esperar por uma condio antes de continuar.

Se voc fizer um loop infinito, voc pode fazer o sistema entrar em deadlock. while (!condition) {} Usar o comando yield evita o deadlock, mas muito ineficiente. while (!condition) {yield()}

Esperando uma condio : wait e notify


wait() parecido com yield(), mas necessita que algum o acorde.
: while (!condition) wait(); //Agora a cond. foi satisfeita :

A thread que pode afetar a condio de espera chama o mtodo notify() para acordar uma das threads que foi dormir. No necessariamente a thread que acorda aquela que queremos, O programador precisa se assegurar que para cada chamada de wait() existe uma chamada correspondente de notify()

Outra soluo
O mtodo notifyAll() habilita todas as threads que esto em estado de wait.

Uma delas ser escalonada e aproveitar da condio satisfeita. As outras, quando forem escalonadas, no tero a condio satisfeita e voltaro a dormir...

Agrupando Threads
Pode-se operar as threads como um grupo.
pode-se parar ou suspender todas as threads de uma s vez.

group.stop();

ThreadGroup g = new ThreadGroup("um grupo de threads");

Agrupando Threads
Inclua uma thread em um grupo atravs do construtor da thread.
Thread t = new Thread(g,new ThreadClass(), "Esta thread");

Agrupando Threads
Para saber quantas threads em um grupo esto sendo executadas no momento, podemos usar o mtodo activeCount():
System.out.println("O nmero de threads "+ " que podem estar rodando "+ g.activeCount());

Gerenciando Threads
java.util.concurrent.Executors
A classe Executors estende a classe raiz Object. A classe Executors gerencia um grupo de threads.
Interface Executor Interface ExecutorService

SingleThreadExecutor usa uma thread para executar atividades seqencialmente. FixedThreadPool usa um grupo de threads de tamanho fixo para executar atividades. CachedThreadPool cria threads sob demanda.

Escalonando Threads
Um ScheduledExecutorService permite escalonar a execuo de atividades, definindo um atraso para incio da atividade e/ou um perodo de repetio entre execues. SingleThreadScheduledExecutor usa uma thread para todas as atividades escalonadas. ScheduledThreadPool cria um grupo de threads para executar as atividades.

Escalonando Threads

Escalonando Threads (Ex 1)

Escalonando Threads (Ex 2)

Escalonando Threads (Ex 3)

Sincronizao
Considere o seguinte cdigo:
public class Contador { private int conta = 0; public int incr() { int n = conta; conta = n + 1; return n; } }

Sincronizao
O que acontece caso tenhamos duas threads que iro executar o mesmo cdigo a seguir?
Ambas as threads esto acessando o mesmo objeto.

int cnt = Contador.incr();

Situao 1

Thread 1 cnt = Contador.incr(); n = conta; conta = n + 1; return n; ---------

Thread 2 --------cnt = Contador.incr(); n = conta; conta = n + 1; return n;

count 0 0 1 1 1 1 2 2

Situao 2

Thread 1 cnt = Contador.incr(); n = conta; --------conta = n + 1; return n;

Thread 2 ----cnt = Contador.incr(); n = conta; conta = n + 1; return n; -----

count 0 0 0 0 1 1 1 1

Monitores
public class Contador2 { private int conta = 0; public synchronized int incr() { int n = conta; conta = n + 1; No permite que este return n; mtodo seja executado } por mais de uma thread } ao mesmo tempo

Monitores
Tambm podemos usar monitores para partes de um mtodo.
synchronized(oObjeto) sentena; // Sincronizada em relao a oObjeto

Indique o recurso a ser monitorado

Monitores
void metodo(UmaClasse obj) { synchronized(obj) { obj.variavel = 5; } }

Ningum poder usar este objeto enquanto estivermos executando estas operaes

Produtor Consumidor
O problema do produtor-consumidor um caso clssico de uma thread que deve esperar por uma condio a ser satisfeita por outras threads. No nosso caso abaixo, o Homer s pode comer biscoitos depois que a Marge os fizer!!!

Marge & Homer


A Marge s assa biscoitos quando precisa, pois a jarra de tamanho limitado. O Homer s os come quando eles existem. Soluo: Marge faz biscoitos, avisa para o Homer que esto prontos e espera. Homer come os biscoitos, avisa para a Marge que eles acabaram e espera.

Produtor e Consumidor
Consumidor synchronized (lock) { while (!resourceAvailable()) { lock.wait(); } consumeResource(); } Produtor produceResource(); synchronized (lock) { lock.notifyAll(); }

Quando o produtor executa, ele tira do estado de wait todos os objetos consumidores que esto esperando sobre o objeto lock

Seqncia de execuo Wait/Notify

1. synchronized(lock){ 2. lock.wait(); 9. consumeResource(); 10. }

Objeto Lock

Thread Consumidor

7. Readquire lock 8. Retorna do wait()

3. produceResource() 4. synchronized(lock) { 5. lock.notify(); 6.}

Thread Produtor

A classe JarraBiscoitos public class CookyJar {


private int contents; private boolean available = false; public synchronized void getCooky(String who) { while (!available) { try {wait();} catch (InterruptedException e) { } } available = false; notifyAll(); System.out.println( who + " ate cooky " + contents); } public synchronized void putCooky(String who, int value) { while (available) { try {wait();} catch (InterruptedException e) { } } contents = value; available = true; System.out.println(who + " put cooky " + contents + " in the jar"); notifyAll(); } }

A classe Homer
public class Homer implements Runnable { CookyJar jar; public Homer(CookyJar jar) { this.jar = jar; } public void eat() { jar.getCooky("Homer"); try { Thread.sleep((int)Math.random() * 1000); } catch (InterruptedException ie) {} } public void run() { for (int i = 1 ; i <= 10 ; i++) eat(); } }

A classe Marge
public class Marge implements Runnable { CookyJar jar; public Marge(CookyJar jar) { this.jar = jar; } public void bake(int cookyNumber) { jar.putCooky("Marge", cookyNumber); try { Thread.sleep((int)Math.random() * 500); } catch (InterruptedException ie) {} } public void run() { for (int i = 0 ; i < 10 ; i++) bake(i); } }

O testador das classes


public class SimpsonsTest { public static void main(String[] args) { CookyJar jar = new CookyJar(); Homer homer = new Homer(jar); Marge marge = new Marge(jar); new Thread(homer).start(); new Thread(marge).start(); } }

Moral da histria : estados possveis de uma Thread


born start() blocked

I/O completed

ready yield()

waiting

wait()

running

sleep()

sleeping

terminate dead

Você também pode gostar