1 Cesar Rocha alunoscesar@gmail.com Cesar Rocha Cesar Rocha alunoscesar@gmail.com alunoscesar@gmail.com
2
Objetivos
§ Explorar os conceitos do uso das ThreadsThreads e sua importância em aplicações multithreads
§ Como criar e gerenciar threads, métodos da API Java,
sincronismo, classe Thread e interface Runnable
§ Escalonamento de threads, conceito de processos ambiente de execução e boas práticas usando Java
§ Alguns problemas relacionados com o uso de
threads: e.g. corrupção de dados (concorrência)
§ Exercícios e vários exemplos de códigos que você
deve testar visando solidificar seus conhecimentos
3
Ambientes multithreads
§ Ambientes multithreads representam uma nova
forma de enxergar o funcionamento de um software
§ Sistemas de software multithreads desempenham
várias atividades de maneira concorrente
§ Estes softwares são capazes de dividir, corretamente, um problema em tarefas menores e independentes
§ Aplicações multithread comuns no nosso dia-a-dia: § Browser, jogos, servidor Web, coletor de lixo, etc...
§ O suporte a multithreading de Java é nativo § Relativamente fácil de usar do que em outras
4
Processos vs. Threads
§ Um processo pode ser entendido como o ambiente onde se pode executar um programa no S.O.
§ O processo é quem irá definir o ambiente, regras, os
seus recursos (buffers, variáveis de ambiente, cópia dos registradores, arquivos, ...) disponíveis a um programa
§ Programa e processo são dois conceitos distintos:
§ Programa = código e processo = a execução
§ Um processo pode chamar vários outros processos (abrir um programa a partir do prompt do DOS, gerando outro processo na memória, por exemplo)
5
Processos vs. Threads
§ Foi visto que um processo é a execução de um
programa juntamente com seus recursos usados
§ A parte “passiva” corresponde aos recursos alocados na hora de iniciar o processo
§ A parte “ativa” corresponde ao fluxo de controle do processo – ou sua linha de execução
§ Um processo pode disparar várias linhas de
execução independentes (chamadas de threads)
§ Elas compartilharão a mesma área de endereçamento
§ Por que não criar outro processo?
§ Existe uma sobrecarga do SO para criar e destruir novos (sub)processos (memória, recursos gerais, etc.)
6
Threads em Java
§ São diferentes linhas de execução (independentes) dentro de um de um processo que roda o programa
§ Também são conhecidas como lightweight process § Um thread “fala e anda” como um programa individual
§ Threads, em Java, são objetos!
§ Sistema garante que, de alguma forma, cada thread tenha acesso à CPU de acordo com:
§ Cotas de tempo (time-slicing), Preempção, ...
§ Programador pode controlar parcialmente forma de
7
Por que usar múltiplas threads?
§ Todo programa tem pelo menos uma thread, que é
conhecida como Main Thread.
§ O método main() roda no Main Thread
§ Em alguns tipos de aplicações, threads adicionais são fundamentais, como:
§ Interfaces gráficas
§ Essencial para ter uma interface ao usuário que
responda enquanto outra tarefa está sendo executada
§ Rede
§ Essencial para que o servidor possa continuar a esperar por outros clientes enquanto lida com as requisições do cliente previamente conectado.
8
Declarando threads em Java
§ Basicamente, existem duas formas possíveis de se criar uma thread em Java:
§ Crie uma classe que herde de java.lang.Thread
§ Implemente a interface java.lang.Runnable
§ Ao herdar da classe Thread:
§ O objeto é um Thread, e sobrepõe o comportamento padrão associado à classe Thread (pouco recomendado)
§ Ao implementar a interface Runnable:
§ O objeto, que define o comportamento da execução, é passado para um Thread que o irá executar (mais recomendado)
§ Nos dois casos:
§ Sobreponha o método run() que é o "main()" do Thread
§ O run() deve conter um loop que irá rodar pelo tempo de vida
9
Exemplo com Thread
public class UsaSapateiro {
public static void main( String[] args ) { Thread sc = new Sapateiro();
sc.start();
System.out.println( "Fim do método main()" ); }
}
public class UsaSapateiro {
public static void main( String[] args ) { Thread sc = new Sapateiro();
sc.start();
System.out.println( "Fim do método main()" ); }
} public class Sapateiro extends Thread {
public Sapateiro(){ this.setName("Sapateiro Comum:"); } public void run() {
for (int marteladas = 1; marteladas <= 10; marteladas++) System.out.println(this.getName() +
" (martelada): " + marteladas ); }
}
public class Sapateiro extends Thread {
public Sapateiro(){ this.setName("Sapateiro Comum:"); }
public void run() {
for (int marteladas = 1; marteladas <= 10; marteladas++) System.out.println(this.getName() +
" (martelada): " + marteladas );
}
}
Não garante a execu Não garante a execuçção ão
imediata! imediata!
Dica:
Dica: o méo método runtodo run() de uma thread () de uma thread equivale ao
equivale ao mainmain() de uma classe() de uma classe
Qual é a saída do programa?
Qual
Qual éé a a sasaíídada do do programaprograma??
Observe alguns Observe alguns m méétodos de todos de Thread Thread
10
Exemplo com Runnable
public class UsaSapateiro {
public static void main( String[] args ) {
Thread sc = new Thread(new SapateiroRunnable()); sc.start();
System.out.println( "Fim do método main()" ); }
}
public class UsaSapateiro {
public static void main( String[] args ) {
Thread sc = new Thread(new SapateiroRunnable()); sc.start();
System.out.println( "Fim do método main()" ); }
} public class SapateiroRunnable implements Runnable { public void run() {
for (int marteladas = 1; marteladas <= 10; marteladas++) System.out.println("Sapateiro Runnable (martelada):"
+ marteladas ); }
}
public class SapateiroRunnable implements Runnable {
public void run() {
for (int marteladas = 1; marteladas <= 10; marteladas++) System.out.println("Sapateiro Runnable (martelada):"
+ marteladas );
}
}
Runnable funciona como Runnable funciona como
o
o ““trabalhotrabalho”” da threadda thread
Qual é a saída do programa?
Qual
Qual éé a a sasaíídada do do programaprograma??
Runnable s
Runnable sóó possui possui um m
um méétodo: todo: runrun()()
11
Declarando threads em Java
§ Como foi visto, a escolha fica entre herdar da classe Thread ou implementar a interface Runnable
§ A primeira abordagem fere alguns conceitos de OO
(herança == especialização de classes)
§ Use herança de tipos para adicionar comportamentos
§ O código (ou o trabalho a ser realizado pela thread) deve ficar dentro do método run()
§ Para disparar uma nova Thread, instancie o objeto e depois envie start() para ele
§ Cuidado! Não chame run() diretamente, ou você estará
12 pú bl ic o in te rn o
Não-determinismo
§ Observe a saída: Acesso proibido! Acesso proibido!public class UsaSapateiro {
public static void main( String[] args ) {
Thread sr = new Thread( new SapateiroRunnable() ); sr.start();
Thread sc = new Sapateiro(); sc.start();
System.out.println( "Fim do método main()" ); ...
public class UsaSapateiro {
public static void main( String[] args ) {
Thread sr = new Thread( new SapateiroRunnable() ); sr.start();
Thread sc = new Sapateiro(); sc.start();
System.out.println( "Fim do método main()" ); ...
Observe os pontos críticos!
Observe
Observe osos pontospontos crcrííticosticos!!
Como pode
Como pode mainmain() ter () ter terminado primeiro? terminado primeiro?
Por que houve uma intercala Por que houve uma intercalaçção ão
das threads, no final? das threads, no final?
13
Estados de transição de uma thread
§ Linhas de execução podem ser:
Œ Novas: o objeto foi instanciado (new), mas não
iniciado com start()
• Passíveis de execução: estão prontas para serem escalonadas pelo sistema operacional ou estão
executando no momento (não há como diferenciar)
Ž Bloqueadas: aguardando o término de uma operação
de E/S, executando um sleep(), executou um
wait() sobre um objeto, bloqueada ao tentar usar um
objeto bloqueado
14
Ciclo de vida
§ Uma thread está geralmente em um dentre três
estados: executável (e possivelmente executando) e
não-executável (esperando, bloqueado,...)
§ A thread entra no estado executável com start() que causa o início de run(), e passa para o estado morto quando run() chega ao fim.
15
Fila de prioridades
§ O estado ready não é garantia de execução. Threads são regidos por prioridades:
16
Principais métodos da classe Thread
§ Estáticos
§ Thread currentThread(): retorna referência para a thread que está executando no momento
§ void sleep(long tempo): faz com que a thread que está
executando pare por um tempo (milissegundos) no mínimo
§ void yield(): faz com que a thread atual pare e permita que outras que estão na sua fila de prioridades executem
§ De instância
§ void run(): é o "main" da Thread. Deve ser implementado na Thread ou no objeto Runnable passado à thread
§ void start(): faz o JVM chamar o run()
17
Sincronismo
§ Até aqui, as threads que vimos eram independentes
§ Não requerem acesso a recursos externos (arquivos,...) § Não precisavam se preocupar com o que estava
ocorrendo com as outras threads em execução
§ Em algumas situações, porém, threads devem compartilhar recursos limitados do sistema
§ E serão obrigadas a se preocupar com outras threads § Dados podem ser corrompidos se uma thread deixar
um objeto num estado incompleto para outra thread
§ Uma thread tentando ler um arquivo enquanto a outra está tentando gravar um dado no mesmo arquivo
18
Sincronismo
§ Num sistema, recursos limitados podem vir a ser compartilhados por várias threads simultaneamente
§ Cada objeto têm um bloqueio que pode ser acionado
pelo método que o acessa/modifica para evitar corrupção de dados
§ O escalonamento é um evento não controlado e imprevisível!
19
Sincronismo
§ Recursos compartilhados devem ser protegidos
§ A palavra synchronized permite que blocos sensíveis ao acesso simultâneo sejam protegidos de corrupção
impedindo que objetos os utilizem ao mesmo tempo.
§ Synchronized deve limitar-se aos trechos críticos
20
Comunicação entre Threads
§ Se um recurso crítico está sendo usado, só uma thread tem acesso. É preciso que:
§ Os outros esperem até que o recurso esteja livre
§ O thread que usa o recurso avise aos outros que o liberou
§ Esse controle é possível através de dois métodos da classe Object, que só podem ser usados em blocos synchronized, veja:
§ wait(): faz com que a Thread sobre a qual é chamado espere por um tempo indeterminado, até receber um... § notify(): notifica a próxima Thread que o recurso
bloqueado foi liberado. Se há mais threads interessadas, use.. § notifyAll(): avisa a todos os threads.
21
Exemplo: produtor e consumidor
§ O seguinte exemplo contém uma classe que denota um recurso compartilhado por duas threads
§ Como os métodos produzir() e consumir() contém
códigos que podem corromper os dados, se não forem executados atomicamente, eles são synchronized
§ A classe tem um local compartilhado para armazenar um
número a ser acessado/modificado por duas threads
§ Para que o exemplo fique interessante…
§ Uma thread (lenta) que irá produzir() 10 números
inteiros e armazená-los no único recurso compartilhado
§ Uma thread (apressada) quer consumir() o número imediatamente
22
Exemplo: produtor e consumidor(1)
§ A thread Produtor irá gerar 10 números e armazená-los no recurso tão logo eles forem consumidos
§ Note que há um retardo de 2 seg. a cada número gerado public class Produtor implements Runnable {
RecursoCompartilhado recurso;
public Produtor( RecursoCompartilhado r ){ this.recurso = r;
}
public void run() {
for ( int i = 1; i <= 10; i++ ) {
recurso.produzir( i ); try { Thread.sleep(2000); } catch (InterruptedException e) { } } } }
A thread tem uma
A thread tem uma
referência para recurso
referência para recurso
compartilhado
compartilhado
O for() ir
O for() iráágerar os 10 gerar os 10 n
núúmeros em seqmeros em seqüüênciaência O m
O méétodo todo sleepsleep() ir() iráá retardar a produ
23
Exemplo: produtor e consumidor(2)
§ A thread Consumidor irá tentar consumir o número em recurso compartilhado imediatamente
§ E se Produtor não tiver gerado o número ainda (lento)? public class Consumidor implements Runnable {
RecursoCompartilhado recurso;
public Consumidor (RecursoCompartilhado r) {
this.recurso = r; }
public void run() {
int numero;
for (int i = 1; i <= 10; i++) { numero = recurso.consumir(); }
} }
A thread tem uma
A thread tem uma
referência para recurso
referência para recurso
compartilhado
compartilhado
Note
Note quequenãonão hháá retardos
24
Exemplo: produtor e consumidor(3)
§ A classe recurso compartilhado (parte 1):
public class RecursoCompartilhado {
int numero; // variável que guarda o número
boolean disponivel = false; // numero disponível ou não public synchronized int consumir(){
while (disponivel == false) {
try { //espere até que produtor gere um valor
wait();
} catch (InterruptedException e) { } }
disponivel = false;
System.out.println("Consumido: " + numero);
// notifique produtor que um numero foi consumido
notifyAll();
return numero; }
public class RecursoCompartilhado {
int numero; // variável que guarda o número
boolean disponivel = false; // numero disponível ou não public synchronized int consumir(){
while (disponivel == false) {
try { //espere até que produtor gere um valor
wait();
} catch (InterruptedException e) { } }
disponivel = false;
System.out.println("Consumido: " + numero);
// notifique produtor que um numero foi consumido
notifyAll(); return numero; } M ét od o co ns um ir ... a classe continua...
25
Exemplo: produtor e consumidor(4)
§ A classe recurso compartilhado (parte 2):
...
public synchronized void produzir( int numero ) { while (disponivel == true) {
try { //espere que consumidor pegue o numero
wait(); } catch (InterruptedException e) { } } this.numero = numero; disponivel = true; System.out.println("Produzido: " + numero);
//notifique consumidor que um numero foi gerado
notifyAll();
}
}// classe
...
public synchronized void produzir( int numero ) { while (disponivel == true) {
try { //espere que consumidor pegue o numero
wait();
} catch (InterruptedException e) { } }
this.numero = numero; disponivel = true;
System.out.println("Produzido: " + numero);
//notifique consumidor que um numero foi gerado
notifyAll(); } }// classe M ét od o pr od uz ir
26
Em resumo…
§ Como sincronizar threads concorrentes?
§ Threads ganham acesso a um recurso adquirindo seu monitor (uma espécie de trava/chave ou “lock”)
§ Somente com o monitor em mãos é que a thread pode acessar partes restritas do código que é crítico
§ Cada objeto Java possui um monitor associado
§ Alguns métodos em um objeto podem exigir um monitor
para serem executados (produzir, consumir, como vimos)
§ Apenas uma thread pode executá-los por vez
§ Haverá um bloqueio do objeto para outras threads
§ Estes métodos são chamados sincronizados
§ Declarados com synchronized
§ Apenas uma thread pode executar um método sincronizado de um objeto por vez (mesmo se houver escalonamento)
27
Para um bom aproveitamento:
Para um bom aproveitamento:
§ Codifique os exemplos mostrados nestes slides e verifique pontos de dúvidas
§ Resolva todas as questões da lista de Threadslista de Threads § Procure o professor ou monitor da disciplina e
questione conceitos, listas, etc.
§ Não deixe para codificar tudo e acumular assunto
para a avaliação.