multithreading

Propaganda
MULTITHREADING
Prof.: Michele Nasu Tomiyama Bucci
Introdução
• O corpo humano realiza uma grande variedade de
operações paralelamente, ou concorrentemente.
• Os computadores também realiza operações
concorrentemente. Porém, apenas computadores que
têm múltiplos processadores podem de fato executar
operações concorrentemente.
• Em computadores de um único processador, os sistemas
operacionais utilizam várias técnicas para simular
concorrência, mas uma única operação pode executar
por vez.
Introdução
• A maioria das linguagens de programação não permitem
que programadores especifiquem atividades
concorrentes.
• Em geral, elas fornecem apenas instruções de controle
que permitem que os programadores realizem uma ação
por vez, avançando para a próxima ação depois de a
anterior ser concluída.
• O Java disponibiliza a concorrência para o programador
de aplicativos por meio de suas APIs.
• O programador especifica os aplicativos que contém
threads de execução, em que cada thread designa uma
parte do programa que pode executar concorrentemente
com outras threads – multithreading.
Introdução
• Um exemplo de multithreading é a coleta de lixo do Java.
• Linguagens como C/C++ exigem que o programador
reivindique memória dinamicamente alocada (free) de
modo explícito (malloc).
• O Java fornece uma thread coletora de lixo que reivindica
a memória que não é mais necessária.
Classe Thread
• A qualquer dado momento, uma thread pode estar em de
seus vários estados de thread:
Estados da Thread
• Uma nova thread inicia seu ciclo de vida no estado
novo. Ela permanece nesse estado até o programa
iniciar a thread, o que a coloca em estado executável (a
thread está executando a sua tarefa).
• Às vezes uma thread entra no estado de espera
enquanto espera outra thread realizar uma tarefa. Uma
vez nesse estado, a thread só volta ao estado executável
quando outra thread sinalizar a thread de espera para
retornar a execução.
Estados da Thread
• Uma thread executável também pode entrar no estado de
espera sincronizada por um intervalo especificado de
tempo. Uma thread nesse estado volta ao estado
executável quando esse intervalo de tempo expira ou
quando ocorre um evento que ele está esperando.
• As threads em espera sincronizada não podem utilizar
um processador, mesmo que haja um disponível.
• Uma thread pode transitar para o estado de espera
sincronizada se fornece um intervalo de espera opcional
quando ela estiver esperando outra thread realizar uma
tarefa.
Estados da Thread
• Outra maneira de colocar uma thread em espera
sincronizada é colocá-la para dormir. Uma thread
adormecida permanece no estado de espera
sincronizada por um período determinado de tempo
(intervalo de adormecimento).
• As threads dormem quando, por um breve período, não
têm de realizar nenhuma tarefa.
• Uma thread entra no estado terminado quando completa
sua tarefa ou termina (condição de erro).
• Exemplo: Processador de texto.
Estados da Thread
• No nível do sistema operacional, o estado executável do
Java na realidade inclui 2 estados separados: pronto e
executando.
Estados da Thread
• Quando uma thread pela 1ª vez no estado executável a
partir do estado novo, a thread está no estado pronto.
• Uma thread pronta entra no estado de execução quando
o sistema operacional atribui a thread a um processador.
– despachar uma thread.
• Na maioria dos sistemas operacionais, cada thread
recebe uma pequena quantidade de tempo de
processador – quantum ou fração de tempo – com a qual
realiza sua tarefa.
Estados da Thread
• Quando o quantum de uma thread expira, a thread
retorna ao estado pronto e o sistema atribuirá outra
thread ao processador.
• O processo que utiliza o sistema operacional para decidir
qual thread despachar é conhecido como agendamento
de thread e depende das prioridades de threads.
Prioridades de Thread e Agendamento de
Thread
• Cada thread Java tem uma prioridade que ajuda o
sistema operacional a determinar a ordem em que as
threads são agendadas.
• MIN_PRIORITY(constante de 1).
• MAX_PRIORITY(constante de 10).
• NORM_PRIORITY(constante de 5).
• Informalmente as threads com prioridade mais alta são
mais importantes para um programa e devem se
alocadas em tempo de processador antes das threads de
prioridade mais baixa.
• Entretanto, as prioridades de thread não podem garantir a
ordem em que elas são executadas.
Prioridades de Thread e Agendamento de
Thread
• O trabalho de um scheduler de thread de sistema
operacional é determinar a próxima thread que entra em
execução.
• Uma simples implementação do scheduler de thread
mantém a thread de prioridade mais alta executando o
tempo todo e, se houver mais de uma thread de
prioridade mais alta, isso assegura que casa uma dalas
executa por um quantum no estilo rodízio.
• As threads A e B vão ficar
executando no estilo rodízio até
que uma das threads torna-se
pronta.
• O processador então dedica-se
a thread que resta.
• Quando a thread termine a
execução, a thread C executa
até a sua conclusão (
considerando que nenhuma
thread de prioridade mais alta
chegará).
• Após, D, E e F entra no rodízio
de execução.
Criando e Executando Threads
• Existem duas formas de criar explicitamente criar
explicitamente um thread em Java:
• Estendendo a classe Thread e instanciando um objeto desta nova
classe.
• Implementando a interface Runnable, e passando um objeto
desta nova classe como argumento do construtor da classe
Thread.
• Nos dois casos a tarefa a ser executado pelo thread
deverá ser descrita pelo método run().
Criando e Executando Threads
• A interface Runnable declara um único método chamado
•
•
•
•
•
run.
Runnables são executados por um objeto de uma
classe que implementa a interface Executor.
Essa interface declara um único método chamado
execute.
Em geral, um objeto Executor cria e gerencia um grupo
de threads denominado de pool de threads.
A interface ExecutorService provê vários outros
métodos para gerenciar o ciclo de vida de um Executor.
O Executor atribui cada Runnable a uma das threads
disponíveis do pool de threads.
Exemplo
• Faça um programa que imprima os números primos
existentes entre 0 e 5000. Utilize threads.
• Para cada faixa de 1000 valores crie uma thread e dispare o
processo para cada uma delas
public class PrimoThread implements Runnable{
private int min;
private int max;
public PrimoThread(int x, int y){
min = x;
max = y;
}
public boolean primo(int x){
for(int i=2; i<x/2+1;i++){
if(x%i==0){
return false;
}
}
return true;
}
public void run(){
//System.out.println("Primos entre: "+min+"-"+max);
for(int i=min; i<=max;i++){
if(primo(i)){
System.out.println(i);
}
}
System.out.println("");
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class PrimoThreadTeste {
public static void main(String args[]){
PrimoThread p1 = new PrimoThread(1, 1000);
PrimoThread p2 = new PrimoThread(1001, 2000);
PrimoThread p3 = new PrimoThread(2001, 3000);
PrimoThread p4 = new PrimoThread(3001, 4000);
PrimoThread p5 = new PrimoThread(4001, 5000);
System.out.println("Starting threads");
ExecutorService threadExecutor = Executors.newFixedThreadPool(5);
threadExecutor.execute(p1);
threadExecutor.execute(p2);
threadExecutor.execute(p3);
threadExecutor.execute(p4);
threadExecutor.execute(p5);
threadExecutor.shutdown();
//System.out.println("Threads Started, main ends");
}
}
Exemplo
• Implemente uma Corrida de Sapos!
• Crie um Classe sapo que herda de Runnable
• Atributos: distanciaPercorrida, distanciaPulo...
• Crie uma Classe Corrida de Sapos
• Atributos: distanciaCorrida, NumSapos
public class SapoThread implements Runnable{
private String nome;
private double distPulo;
private double distPercorrido;
private double distMax;
public SapoThread(String n, double pu, double pe, double dm){
nome=n;
distPulo=pu;
distPercorrido=pe;
distMax=dm;
}
public void run(){
while(distPercorrido<distMax){
distPercorrido+=distPulo;
System.out.println(nome+" Chegou!");
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SapoThreadTeste {
public static void main(String args[]){
double dist = 10.0;
SapoThread s1 = new SapoThread("Sapo1",0.5,0.0,dist);
SapoThread s2 = new SapoThread("Sapo2",0.3,0.0,dist);
SapoThread s3 = new SapoThread("Sapo3",0.9,0.0,dist);
SapoThread s4 = new SapoThread("Sapo4",0.6,0.0,dist);
SapoThread s5 = new SapoThread("Sapo5",0.4,0.0,dist);
ExecutorService threadExecutor = Executors.newFixedThreadPool(5);
threadExecutor.execute(s1);
threadExecutor.execute(s2);
threadExecutor.execute(s3);
threadExecutor.execute(s4);
threadExecutor.execute(s5);
threadExecutor.shutdown();
}
}
Download