24
MULTITHREADING Prof.: Michele Nasu Tomiyama Bucci

Multithreading - FACOM

  • Upload
    others

  • View
    30

  • Download
    0

Embed Size (px)

Citation preview

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();

}

}