Buscar

THREADS E CONCORRENCIA EM JAVA

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 12 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 12 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 12 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

1 
THREADS E CONCORRENCIA EM JAVA – PROF. EDIBERTO 
 
Thread é a tarefa que um determinado programa realiza. Fio de execução, também 
conhecido como linha ou encadeamento de execução, (em inglês: Thread), é uma 
forma de um processo dividir a si mesmo em duas ou mais tarefas que podem 
ser executadas concorrencialmente. 
 
Porque usar threads? Para se rodar um programa puramente sequencial 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Exemplos de usos 
Um exemplo simples seria um jogo, que pode ser modelado com linhas de 
execução diferentes, sendo uma para desenho de imagem e outra para áudio. 
Neste caso, há um thread para tratar rotinas de desenho e outro thread para 
tratar áudio; No ponto de vista do usuário, a imagem é desenhada ao mesmo tempo 
em que o áudio é emitido pelos alto-falantes; Porém, para sistemas com uma única 
CPU, cada linha de execução é processada por vez. 
Vantagens do uso de Threads 
 Simplificação do modelo de programação: Em muitas aplicações ocorrem 
múltiplas atividades simultaneamente, e algumas delas podem ser 
bloqueadas de tempos em tempos. Ao decompor uma aplicação em múltiplos 
threads sequenciais que executam quase em paralelo, há uma simplificação 
do modelo de programação. 
 
Processo 
Thread 
Thread 
Thread 
Thread Thread 
Thread 
Thread Thread 
 2 
 Threads são mais rápidos de criar e destruir se comparado aos 
processos, uma vez que não possuem quaisquer recursos associados a eles. 
 
 Desempenho: quando há grande quantidade de computação e de E/S, os 
threads permitem que essas atividades se sobreponham, acelerando a 
aplicação. 
 
Particularidades 
Cada thread tem o mesmo contexto de software e compartilha o mesmo 
espaço de memória (endereçado a um mesmo processo-pai), porém 
o contexto de hardware é diferente. Sendo assim o overhead causado pelo 
escalonamento de uma thread é muito menor do que o escalonamento de 
processos. Entretanto, algumas linguagens (C, por exemplo) não fornecem 
acesso protegido à memória nativa (sua implementação fica a cargo do 
programador ou de uma biblioteca externa) devido ao compartilhamento do 
espaço de memória. 
Um dos benefícios do uso das threads advém do fato do processo poder ser 
dividido em várias threads; quando uma thread está à espera de determinado 
dispositivo de entrada/saída ou qualquer outro recurso do sistema, o 
processo como um todo não fica parado, pois quando uma thread entra no 
estado de 'bloqueio', uma outra thread aguarda na fila de prontos para 
executar. 
Uma thread possui um conjunto de comportamentos padrão, normalmente 
encontrados em qualquer implementação ou sistema operativo. 
 
Uma thread pode: 
 criar outra da mesma forma que um processo, através do método thread-
create, onde a thread retorna um ID como primeiro argumento (resultado da 
função de criação); 
 
 esperar outra thread se sincronizar, através do método join; 
 
 voluntariamente "desistir" da CPU por não precisar mais do processamento 
proposto pela própria ou por vontade do utilizador. Feito através do 
método thread-yield; 
 
 replicar-se sem a necessidade de duplicar todo o processo, economizando 
assim memória, processamento da CPU e aproveitando o contexto (variáveis, 
descritores, dispositivos de I/O). 
 
 
 
 
 
 3 
Threads em Java 
Em Java, usamos a classe Thread do pacote java.lang para criarmos linhas 
de execução paralelas. A classe Thread recebe como argumento um objeto com o 
código que desejamos rodar. 
Exemplo: 
public class GeraPDF { 
 public void rodar () { 
 // lógica para gerar o pdf... 
 } 
} 
 
public class BarraDeProgresso { 
 public void rodar () { 
 // mostra barra de progresso e vai atualizando ela... 
 } 
} 
E, no método main, criamos os objetos e passamos para a classe Thread. O 
método start é responsável por iniciar a execução da Thread: 
 
Exemplo: 
public class MeuPrograma { 
 public static void main (String[] args) { 
 
 GeraPDF gerapdf = new GeraPDF(); 
 Thread threadDoPdf = new Thread(gerapdf); 
 threadDoPdf.start(); 
 
 BarraDeProgresso barraDeProgresso = new BarraDeProgresso(); 
 Thread threadDaBarra = new Thread(barraDeProgresso); 
 threadDaBarra.start(); 
 
 } 
} 
O código acima, porém, não irá compilar. Como a classe Thread sabe que 
deve chamar o método rodar? Como ela sabe que nome de método daremos e que 
ela deve chamar esse método especial? Falta na verdade um contrato entre as 
nossas classes a serem executadas e a classe Thread. 
 
CONTRATO 
Esse contrato existe e é feito pela interface Runnable: devemos dizer que 
nossa classe é "executável" e que segue esse contrato. Na interface Runnable, há 
apenas um método chamado run. Basta implementá-lo, "assinar" o contrato e a 
classe Thread já saberá executar nossa classe. 
 
 
 
 
 4 
Exemplo1: 
public class GeraPDF implements Runnable { 
 public void run () { 
 // lógica para gerar o pdf... 
 } 
} 
 
Exemplo2: 
public class BarraDeProgresso implements Runnable { 
 public void run () { 
 // mostra barra de progresso e vai atualizando ela... 
 } 
} 
A classe Thread recebe no construtor um objeto que é um Runnable, e seu 
método start chama o método run da nossa classe. Repare que a 
classe Thread não sabe qual é o tipo específico da nossa classe; para ela, basta 
saber que a classe segue o contrato estabelecido e possui o método run. 
OBS. É o bom uso de interfaces, contratos e polimorfismo na prática! 
Ciclo de Vida de um Thread 
Num certo momento, o thread pode estar em um entre vários estados e 
podemos identificar os estado e como transições ocorrem entre estados como 
mostra a figura abaixo 
Esse tipo de diagrama chama-se também "diagrama de estados finito" (porque o 
número de estados é finito). 
O diagrama abaixo não está completo, mas mostra as partes essenciais da vida 
de um thread. 
 
 O thread está "pronto para rodar" 
 Se a máquina tiver um único processador, só se pode rodar de verdade um 
thread de cada vez. 
 O sistema Java (JVM) deve implementar um esquema de escalonamento que 
compartilhe a CPU entre todos os threads que estão no estado "Runnable" 
 5 
 Portanto, um thread que está no estado "Runnable" pode, de fato, estar 
esperando a CPU. 
O primeiro argumento do construtor de Thread deve ser um objeto que 
implemente a interface Runnable. 
 
Obs. 
Existe apenas uma forma de se criar explicitamente uma thread em Java: 
estendendo-se a classe Thread 
 
Exemplo: 
public class Thread01 implements Runnable { 
 ... 
 … 
} 
 
Iniciando um thread - start() 
 A próxima linha (em destaque abaixo) aloca os recursos necessários para 
executar um thread (pilha, etc.). 
Exemplo: 
public void start() { 
 … 
 Thread01.start(); 
} 
Executando um thread - run() 
Depois que start() retorna, o thread está no estado "Runnable". 
Exemplo: 
public void run() { 
 Thread01 proc1 = new Thread01(); 
 … 
 Thread thread1 = new Thread(proc1); 
 thread1.start(); 
 } 
 
 
 
 
 
 
 
 
 6 
Estado Non-Runnable (PARADO) de um THREAD 
 
método sleep() e método wait() 
Um thread passa a ser "Non-Runnable" quando um dos seguintes eventos 
ocorre: 
1 - O método sleep() é chamado. 
2 - O thread chama o método wait() que espera por uma condição. 
O thread faz um system call "lento" tal como um system call que causa I/O 
Também fala-se que o thread está "bloqueado" esperando algo. 
 
Thread Dormindo 
Para que a thread atual durma basta chamar o método a seguir, por exemplo, 
para dormir 3 segundos: 
Thread.sleep(3 * 1000); 
 
Exemplo: 
Thread thread2 = newThread(proc2); 
 try { 
 thread2.sleep(3*1000); 
 thread2.start(); 
 } catch (InterruptedException e) { 
 thread2.start(); 
 } 
 
Quando o thread está dormindo, ele não roda, mesmo que a CPU esteja 
livre. 
 
Para cada forma de entrar no estado Non-Runnable, alguma forma específica 
fará o thread retornar para o estado Runnable. 
 
Ex.: para retornar de sleep, tempo tem que passar. 
Ex.: para retornar de wait, outro objeto vai ter que fazer a condição ocorrer 
através de uma chamada a notify(). 
Ex.: para retornar de I/O lento, o I/O tem que terminar 
 
Em relação às threads no Java: 
- Só se pode usar wait, notify() e notifyAll() quando se está de posse do lock 
do objeto. 
- Há três versões do método wait() da classe Object. 
- wait() espera uma condição para o objeto corrente e esta condição ocorre 
com notify() no mesmo objeto. 
 7 
- "Ter posse do lock" também se chama "possuir o monitor do objeto". 
 
Parando um thread 
Há método stop() para parar um thread mas ele não deve ser usado, devido 
está "deprecated" porque descobriu-se que o método tem problemas (é 
"inseguro"). 
A outra forma é fazer com que o thread saque que ele tem que parar e retornar 
do método run(), usando um loop ou o método stop(). Conforme seguem a 
sintaxe: 
Loop: 
 public void run() { 
 int i = 0; 
 while (i < 100) { 
 i++; 
 System.out.println("i = " + i); 
 } 
 } 
 
método stop(). 
Thread thread2 = new Thread(proc2); 
 
thread2 = null; 
 
 
Multithreading 
A concorrência de dados é um dos principais problemas a se enfrentar quando 
empregamos multithreading. Ela é capaz de gerar, desde inconsistência nos dados 
compartilhados, até erros em tempo de execução. No entanto, felizmente isto pode 
ser evitado, sendo necessário se precaver para que o aplicativo não apresente tais 
problemas. 
Uma boa forma de evitar problemas de concorrência é sincronizar as threads 
que compartilham dados entre si. A partir disso, estas threads passam a executar 
em sincronia com outras, e assim, uma por vez acessará o recurso. 
 
 
 
 
 
 
 8 
ESCALONADOR E TROCAS DE CONTEXTO 
(execução em paralelo) 
Quando queremos executar várias coisas ao mesmo tempo, e o processador 
só consegue fazer uma coisa de cada vez? Entra em cena o escalonador de 
threads. 
 
O escalonador (scheduler), sabendo que apenas uma coisa pode ser 
executada de cada vez, pega todas as threads que precisam ser executadas e 
faz o processador ficar alternando a execução de cada uma delas. A ideia é 
executar um pouco de cada thread e fazer essa troca tão rapidamente que a 
impressão que fica é que as coisas estão sendo feitas ao mesmo tempo. 
O escalonador é responsável por escolher qual a próxima thread a ser 
executada e fazer a troca de contexto (context switch). Ele primeiro salva o estado 
da execução da thread atual para depois poder retomar a execução da mesma. Aí 
ele restaura o estado da thread que vai ser executada e faz o processador continuar 
a execução desta. Depois de um certo tempo, esta thread é tirada do processador, 
seu estado (o contexto) é salvo e outra thread é colocada em execução. A troca de 
contexto é justamente as operações de salvar o contexto da thread atual e restaurar 
o da thread que vai ser executada em seguida. 
Quando fazer a troca de contexto, por quanto tempo a thread vai rodar e 
qual vai ser a próxima thread a ser executada, são escolhas do escalonador. 
Nós não controlamos essas escolhas (embora possamos dar "dicas" ao 
escalonador). Por isso que nunca sabemos ao certo a ordem em que programas 
paralelos são executados. 
Todo esse processo é feito automaticamente pelo escalonador do Java (e, 
mais amplamente, pelo escalonador do sistema operacional). Para nós, 
programadores das threads, é como se as coisas estivessem sendo executadas 
ao mesmo tempo. 
Computadores de mais de um processador: 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 CPU Core 1 CPU Core 0 CPU Core 2 
 
 
Processo 
Thread 0 Thread 1 Thread 2 
 9 
A VM do Java e a maioria dos SOs modernos consegue fazer proveito de 
sistemas com vários processadores ou multi-core. A diferença é que agora temos 
mais de um processador executando coisas e teremos, sim, execuções 
verdadeiramente paralelas. 
Mas o número de processos no SO e o número de Threads paralelas 
costumam ser tão grandes que, mesmo com vários processadores, temos as trocas 
de contexto. A diferença é que o escalonador tem dois ou mais processadores para 
executar suas threads. Mas dificilmente terá uma máquina com mais processadores 
que threads paralelas executando. 
Exemplo: 
package control; 
public class Thread01 implements Runnable { 
 private int codigo; 
 // colocar getter e setter para o atributo codigo 
 public int getCodigo() { 
 return codigo; 
 } 
 public void setCodigo(int codigo) { 
 this.codigo = codigo; 
 } 
 public void run () { 
 for (int i = 0; i < 10; i++) { 
 System.out.println("Processamento " + codigo + " valor: " + i); 
 } 
 } 
} 
package model; 
import control.Thread01; 
public class ExecutaThread01 { 
 public static void main(String[] args) { 
 
 Thread01 proc1 = new Thread01(); 
 proc1.setCodigo(1); 
 
 Thread thread1 = new Thread(proc1); 
 thread1.start(); 
 
 Thread01 proc2 = new Thread01(); 
 proc2.setCodigo(2); 
 
 Thread thread2 = new Thread(proc2); 
 thread2.start(); 
 
 } 
} 
 10 
 
SAÍDAS 
 
 1ª Execução 2ª Execução 3ª Execução 
 
 
THREAD DORMINDO dormindo 3 segundos 
Exemplo: 
package control; 
public class Thread01 implements Runnable { 
 private int codigo; 
 // colocar getter e setter para o atributo codigo 
 public int getCodigo() { 
 return codigo; 
 } 
 public void setCodigo(int codigo) { 
 this.codigo = codigo; 
 } 
 public void run () { 
 for (int i = 1; i <= 10; i++) { 
 System.out.println("Procesamento " + codigo + " valor: " + i); 
 } 
 } 
} 
package model; 
import control.Thread01; 
public class ExecutaThread01 { 
 @SuppressWarnings("static-access") 
 public static void main(String[] args) { 
 Thread01 proc1 = new Thread01(); 
 proc1.setCodigo(1); 
 Thread thread1 = new Thread(proc1); 
 thread1.start(); 
 11 
 Thread01 proc2 = new Thread01(); 
 proc2.setCodigo(2); 
 Thread thread2 = new Thread(proc2); 
 try { 
 thread2.sleep(3*1000); 
 thread2.start(); 
 } catch (InterruptedException e){ 
 thread2.start(); 
 } 
 } 
 } 
SAÍDAS 
 
 
 
DEPOIS DE 3 SEGUNDOS 
 
 
 
 
 
 
 
 
 
 12 
Parando um thread - (thread = null) 
Exemplo 
package control; 
public class Thread01 implements Runnable { 
 private int codigo; 
 // colocar getter e setter para o atributo codigo 
 public int getCodigo() { 
 return codigo; 
 } 
 public void setCodigo(int codigo) { 
 this.codigo = codigo; 
 } 
 public void run () { 
 for (int i = 1; i <= 10; i++) { 
 
 System.out.println("Procesamento " + codigo + " valor: " + i); 
 } 
 } 
} 
package model; 
import control.Thread01; 
public class ExecutaThread01 { 
 @SuppressWarnings("static-access") 
 public static void main(String[] args) { 
 Thread01 proc1 = new Thread01(); 
 proc1.setCodigo(1); 
 Thread thread1 = new Thread(proc1); 
 thread1.start();Thread01 proc2 = new Thread01(); 
 proc2.setCodigo(2); 
 
 Thread thread2 = new Thread(proc2); 
 thread2 = null; 
 } 
 } 
SAÍDA

Continue navegando