terça-feira, 25 de agosto de 2009

Modelos de Escalonamento, Prioridade de threads

Escalonamento,Caracterização de threads, Prioridades , modelos de threads:

Source: Java threads 2nd Edition

Sumário: Escalonamento,CPU intensive,I/O intesive, Interactive,Prioridades de thread, Round-Robin,Modelos de thread


Considerações Iniciais:

- O modelo de escalonamento de threads em java não é definido por uma especificação, isso significa que o comportamento varia de plataforma(Nativa) para plataforma(Nativa).

- Java é uma plataforma independente, oque implica a não necessitar saber sobre detalhes de implementação da Plataforma Nativa POREM em alguns casos os detalhes importam!

- Na maioria dos computadores temos somente uma CPU e programas multiThread, e oque acontece é que nem todas as threads estarão Running em paralelo realmente já que, cada CPU é "entregue" a cada thread. Quem determina qual thread esta hábil a ser Running é o ESCALONADOR.


CPU e threads:

O ponto mais importante a intender é que a CPU é um recurso escaço. Quando temos duas threads querendo entrar no estado de Running em um computador com apenas uma CPU ou um core,essas duas vão competir pela CPU, e fica a encargo de alguem realmente afirmar que essa CPU(esse único core) sera realmente dividido entre as threads, ou qual sera escolhida para ser RUNNING- e quem é decide é programador, ou a JVM ou ao S.O.. O ponto vital é, COMO DIVIDIR uma CPU para que threads tenham acesso.

Outro ponto importante é intender que a preocupação de como o escalonamento de threads é feito, é só realmente dado a threads que querem compartilhar a mesma CPU, porem por longos períodos de tempo. Threads por exemplo que ficam aguardando dados, não são preocupantes pois elas ficam aguardando e quando obtém logo, processam e já voltam ao estado de espera.(ou seja, elas ficam em Blocked. E quando os dados estão la, se as outras forem de mesma prioridade, simplesmente ela vai para RUNNING faz oque tem que fazer, e volta para Blocked para esperar mais), as Threads que pegam a CPU rapidamente e já devolvem não são problemas.

NÃO PODEMOS GARANTIR A ORDEM DE IMPLEMENTAÇÃO DAS THREADS, JÁ QUE A PROPRIA ESPECIFICAÇÃO DA UMA IDÉIA SOBRE ISSO, CADA JVM OPERA DE UMA MANEIRA.(Isso se as threads forem de mesma prioridade, se forem de diferente ai dá)

A preocupação DE THREADS SO DEVE OCORRER QUANDO TEMOS MAIS DE UMA THREAD QUE AMBAS SÃO - CPU INTENSIVE- ISSO AINDA SE ELAS USAREM UMA GRANDE QUANTIDADE DE TEMPO DIRETO.(E se o resultado intermediário for importante).


Caracterizando programas: - Um simples programa pode pertencer a todas essas fases ou ir através de todas essas. -


CPU intensive:
São programas que requerem vários ciclos para completarem sua tarefa. Eles requerem uma certa porção de tempo da CPU e quase não requerem Input, ou requerem muito pouca, nem de usuário nem de Qualquer outro Source.


I/O intensive:
São programas que a maior parte de tempo ficam aguardando por dados de I/O. Esperando dados de um socket, escrevendo dados de para um Socket, Lendo dados do disco(Quando tiver) etc.


Interactive:
São programas que agem quando o usuário age. Ex: Quando o usuário faz uma determinada ação(Interactive) ai sim o programa entra em um CPU intensive ou I/O intensive. Um TCP server é um exemplo, o TcpServer aguarda o usuário se conectar e não um Input do usuario(I/O intensive).


Escalonamento de threads:

class TestThread extends Thread {

String id;

public TestThread(String s) {

id = s;

}

public void doCalc(int i) {

// Perform complex calculation based on i.

}

public void run() {

int i;

for (int i = 0; i <>

doCalc(i);

System.out.println(id);

}

}

}

public class Test {

public static void main(String args[]) {

TestThread t1, t2, t3;

t1 = new TestThread("Thread 1");

t1.start();

t2 = new TestThread("Thread 2");

t2.start();

t3 = new TestThread("Thread 3");

t3.start();

}

}


- Se executar o código acima, muitas das vezes darão resultados diferentes e imparciais.

- O cuidado com relação a um programa multithread deve ser alto pois, dependendo do escalonador e da JVM a falta de “manipulação”por falta do programador lega a programas com respostas incoerentes em diversas JVMS e S.O.(s).


Oque acontece quando eu tenho varias threads.start()?

Oque normalmente ocorre é que temos muitas threads no estado RUNNABLE, aguardando em um Pool, onde serão selecionadas uma a uma, para se tornarem RUNNING.


Como eu sei qual das threads no Pool de Runnable será escolhida para ser Running?

O escalonador de java é baseado na prioridade das threads. Isso significa que as threads são assinadas com uma certa prioridade, um valor inteiro positivo. APENAS O PROGRAMADOR pode trocar a prioridade. Ou seja se uma thread nasce com uma prioridade, mesmo que ela passe por todos os estados possíveis, ela morrerá com a mesma prioridade.


O valor da prioridade de uma thread é tão importante assim?

O principio de uma escalonador de java é que , a thread que estiver em estado RUNNING, é aquela que tem a maior prioridade de todas no pool de RUNNABLES.

OQUE acontece quando uma thread de alta prioridade entra no estado RUNNABLE?

A jvm, interrompe qualquer thread que esteja em estado RUNNING(Claro se ela tiver prioridade menor) e manda para RUNNABLE, e a thread de maior prioridade que esta no Pool de Runnable, será a que estará no estado RUNNING agora.



Prioridade de threads:


public class SchedulingExample {

public static void main(String args[]) {


Thread calcThread = new Thread();

calcThread.setPriority(4);

calcThread.start();


AsyncReadSocket reader;

reader = new AsyncReadSocket(new Socket(host, port));

reader.setPriority(6);

reader.start();


doDefault();

}

public void run() {


}

}


Explicando:

- Temos 3 threads no determinado programa, main, calcThread e reader.

- main, simplesmente faz a inicialização das outras 2, e ao fim chama o método doDefault() - main tem prioridade 5

- calcThread é uma thread qualquer, que foi configurada com prioridade 4

- reader é uma thread de leitura de InputStream de um socket, e tem prioridade configurada para 6

Dentro do code_block de main, estamos executando o código, e na instrução calcThread.start() o escalonador sabe agora que temos 2 threads(a main, e a calcThread)- Então main e calcThread vão para o estado RUNNABLE para a avaliação. Como a calcThread tem prioridade 4, a calcThread fica no estado RUNNABLE e a main continua no estado RUNNING já que tem prioridade 5.

Na segunda parte da thread main, quando invocamos reader.start() , a thread reader entra no estado de RUNNABLE e main também, as duas vão para a avaliação. Como reader tem uma prioridade maior que main, reader se torna a thread no estado RUNNING que só deixará de ser Running a partir do momento que se tornar RUNNABLE ou DEAD ou BLOCKED,pode ser por controles do programador ou por termino do code_block.(Lembre-se de uma coisa, a thread reader é uma thread de leitura de fluxo de bytes, ou seja se não tiver nada para ler na entrada do SOCKET a thread reader ENTRA NO ESTADO BLOCKED.).

A thread reader entrando no estado BLOCKED leva o escalonador a fazer uma escolha no POOL de runnables, no POOL temos a main thread e a calcThread thread, como a main tem maior prioridade ela é escolhida pelo escalonador e se tornará RUNNING, a thread main so ficará no estado de RUNNING, enquanto a thread reader estiver no estado BLOCKED.

Suponto que a thread reader saia do estado BLOCKED, ela vai para o estado RUNNABLE, oque traz a main thread de volta para o estado RUNNABLE, e vem a avaliação, sendo como de se esperar a thread reader tem maior prioridade e se torna a thread RUNNING, e a thread main fica no estado RUNNABLE.

A thread calcThread ficará no estado Runnable até que as outras 2 entrem no estado BLOCKED ou terminem o seu code_block, ou seja, vai demorar. a thread calcThread entrar noque chamamos de CPU Starvation(inanição).

A JVM NUNCA AJUSTA A PRIORIDADE DE ALGUMA THREAD PARA BALANCEAR ISSO, LEMBRE-SE SO QUEM PODE FAZER ISSO É O PROGRAMADOR.


Threads de Mesma Prioridade:

Considerações: Não existe uma implementação padrão para threads de mesma prioridade, deriva de JVM para JVM e de S.O. Para S.O. Por isso da importância da intervenção do programador. Esse modelo apresentado a seguir é um muito usado, porem não é uma especificação para todos.


Um modelo muito usado de escalonamento:

Vamos considerar que a JVM tem o controle de quais threads ela tem, em uma Lista. Então temos uma lista de todas as threads no estado new,uma lista de todas as threads no estado bloqueado,uma lista de todas as threads no estado dead, uma lista de todas as threads por prioridade.(essas listas são tipo - o pool delas)

Então toda thread esta em uma lista , que representa o seu estado. A lista de threads por prioridade é o seguinte, só entra na lista a thread da mesma prioridade da lista e SE ESTIVER NO ESTADO RUNNABLE

ex: uma thread de prioridade 7 só entra na lista de prioridade 7 se estiver no estado RUNNABLE. Temos as mesmas coisas para as 11 prioridades existentes.

Essa threads estão em uma lista ORDENADA, que dirá qual thread terá a oportunidade de se tornar RUNNING.

Vamos dizer agora que calcThread tem a mesma prioridade que main.


public class SchedulingExample {

public static void main(String args[]) {


Thread calcThread = new Thread();

calcThread.setPriority(5);

calcThread.start();


AsyncReadSocket reader;

reader = new AsyncReadSocket(new Socket(host, port));

reader.setPriority(6);

reader.start();


doDefault();

}

public void run() {


}

}

- Agora funcionará assim, - É apenas um modelo de implementação

A thread que esta executada é sempre:

A ultima thread de mais alta prioridade de uma lista não vazia(ou seja tem que ter alguma thread na lista )- Essa thread estava na cabeça(na ponta da lista) quando ela foi selecionada para ser a thread que será RUNNING, então a thread vai para o fim da lista.

(Ou seja, o escalonador ve as prioridades, a lista escolhida é a de maior prioridade, se ELA Não for vazia(null))

No nosso caso, temos as listas{Prioridade 5, Prioridade 6, Blocked }só vamos citar essas, porque é a que vamos usar então é as que nos interessa.

Tudo ocorre normal, Enquanto só estamos na thread main, somente ela é executada, quando invocamos calcThread.start(), agora sim TEMOS 2 THREADS DISPUTANDO PELA CPU, DE MESMA PRIORIDADE.


ANTES:

calcThread.start(); - quer dizer, aqui o escalonador coloca a thread na lista

(Como ela foi start agora, ela é a mais recomendada das de mesma prioridade, portanto ela entra direto, e NESSE CASO ela já vai pra RUNNING) - a regra só vale para depois de start()- Mais mesmo assim em muitos escalonadores, essa calcThread segue a regra de fila é muito relativo.

Prioridade 5

Prioridade 6

BLOCKED

main

null(vazia)

null(vazia)

calcThread




DEPOIS:

Depois de algum tempo, que o escalonador dividiu entre as threads(a CPU), ele volta para a thread main, ou seja a thread main foi selecionada para ser RUNNING, então ela vai para o fim da lista(Voltou pois elas tem a mesma prioridade e aconteceu timeSlicing)


Prioridade 5

Prioridade 6

BLOCKED

calcThread

null(vazia)

null(vazia)

main



*** A thread main é a que esta RUNNING no momento

*** A jvm joga as duas threads para RUNNABLE e avalia a situação desse jeito.

Conseqüentemente so temos uma lista que contem threads, a lista - Prioridade 5 - as outras estão vazias, dentro da lista, a ultima thread a entrar foi a calcThread.

Voltando para o código do metodo main, temos agora


reader.start(); que fará isso:


Prioridade 5

Prioridade 6

BLOCKED

calcThread

reader

null(vazia)

main



Logico que agora a thread que será executada é a de maior prioridade ou seja a reader, e como prioridade não se altera, somente o programador pode, ela fica ate virar BLOCKED,mais como ela esta aguardando dados, então reader entra em BLOCKED. Sendo assim a JVM procura por uma lista não vazia e acha a de Prioridade 5, a primeira da lista é calcThread sendo assim ela é selecionada para ser RUNNING e vai para o fim da fila.


Prioridade 5

Prioridade 6

BLOCKED

main

null(vazia)

readerl(I/O intensive)

calcThread




E ASSIM POR DIANTE, TODA VEZ QUE READER SAIR DE BLOCKED TODAS VÃO PARA RUNNABLE O ESCALONADOR AVALIA, E READER É A DE MAIS PRIORIDADE E SE TORNA RUNNING, QUANDO READER FICA BLOCKED DE NOVO, será a do topo da lista de Prioridade 5....Se você percebeu toda vez que reader bloquear entrara uma diferente de prioridade 5, elas ficam alternando. FICAMOS Naquela regra, a primeira thread da lista de prioridade é selecionada para ser RUNNING e vai para o fim da fila.


Round-Robin Scheduling

Algumas Jvms usam o Round-robin do S.O. - Não tem nada que diga exatamente para uma JVM não implementar o escalonador Round-robin, porem as “manipulações” do programador podem evitar de vir a ocorrer.

- Round-robin é um algoritmo de escalonamento usado em computadores no qual um número determinado de processos ocorrem com um intervalo de tempo também determinado. - Ele usa aquele conceito de lista, oque estiver em cima é executado e vai pro fundo.(ELE É implementando em alguns S.O.) - E DELE SURGI O CONCEITO DE Time-slicing .

- Time-slicing é um termo que vem de múltiplas threads no estado "Runnable" de mesma prioridade que são as de mais alta prioridade no sistema e estão competindo pela CPU(ou seja um pc só com uma CPU, e elas querem se tornar RUNNING).

- Em alguns S.O.(s) A JVM não usa o Round-robin do proprio S.O. Portanto quando, uma thread de mesma prioridade esta em RUNNING e outra em RUNNABLE, a que esta em RUNNABLE so se tornara RUNNING se o programador fizer alguma intervenção do tipo(sleep(), wait() etc.)


O escalonador Round-robin é mais implementado em JVMs que atuam em plataformas Windowns, ou seja a maioria das plataformas derivadas de UNIX não tem essa implementação de escalonador.

OU SEJA AQUELA HISTORIA DE FILA E THREAD SO ACONTECE EM ALGUNS S.O. EM OUTROS SO É VALIDO A REGRA DE PRIORIDADE.

TUDO DEPENDE DO S.O. e da máquina virtual.(já que a versão da JVM é especifica a cada S.O.)


Modelos de threads:

A UNICA AFIRMAÇÃO AO CERTO QUE PODEMOS DAR É DE QUE, UMA THREAD DE PRIORIDADE MAIS ALTA, É SEMPRE EXECUTADA COMO PREFERENCIA ANTES DE UMA DE PRIORIDADE MENOR.

Um grande problema é que, muitos S.O. Não sabem dizer ao certo quando uma thread sai do estado BLOCKED e entra no estado RUNNABLE, Existe uma pequena quantidade de tempo entre quando uma thread de alta prioridade BLOCKED se torna RUNNABLE e quando ela realmente se torna RUNNING. Mais são coisas que não fazem muita diferença no dia dia, é uma questão de um pequeno delay.

Se tiver um pequeno espaço de tempo entre quando os dados chegam no Socket e quando a thread é desbloqueada para poder ler os dados do Socket,o seu programa não saberá, a única coisa que acontecerá é que ele assumira que os dados demoraram um pouco mais que o esperado.


Temos 2 tipos de modelos básicos de threads:


The green-thread model - as threads são gerenciadas somente pela JVM.É o modelo mais comum. O qual estamos falando dele.

The native-thread model - as threads são gerenciadas pelo S.O. que é hosta da JVM, como é do S.O tende a ser parecido, onde entram recursos e melhorias de cada S.O. Em particular.


Quando o escalonamento é importante?

Grande parte desses detalhes não faz diferença nos seus programas , porque a maior parte das threads que você usar são aquelas que ficam bloqueadas esperando dados (I/O intensive)

Ex: read() para ler InputStream de um Socket, ou o Thread.sleep() para parecer um timer ou o wait() para notificar algo. Se a intenção é somente que as tarefas sejam feitas , não precisa se incomodar com o SCHEDULER.

Normalmente threads ficam indo de BLOCKED para RUNNABLE, de RUNNABLE para BLOCKED. E como a maior parte das threads ficam bloqueadas ou alternando, sempre temos a OPORTUNIDADE DE OUTRAS THREADS se tornarem RUNNING. E no caso das threads que não ficam bloqueadas , faz somente uma tarefa em específico e termina essa tarefa.


Exemplo: Um programa que captura 4 partes de uma imagem e faz uma conta, tem que esperar as 4 partes e as 4 contas ficarem prontas para mostrar a imagem. Tanto faz se temos a intervenção do Round-robin ou não, Tudo que queremos é o resultado FINAL.


QUANDO DEVO TOMAR CUIDADO?

- Quando tenho mais de um CPU-Intensive no programa

- Quando resultados parciais são importantes(Se eu quero ver cada parte da imagem quando ficar pronta antes de ver as 4 juntas)

- Quando threads não estão fazendo uma tarefa associada; as threads estão fornecendo tarefas separadas que vão se integrando, ou empregando um paradigma de round-robin scheduling(Um programa de servidor que responde a requisições de diferentes usuários) ou empregando um paradigma de Escalonador(um servidor que processa requisições de usuarios )


Exemplos práticos de Round-Robin Scheduling


Com Round-Robin(ou seja liberando o conceito de TimeSlicing)

Thread #1, tick = 50000

Thread #0, tick = 50000

Thread #0, tick = 100000

Thread #1, tick = 100000


Sem Round-Robin

Thread #0, tick = 50000

Thread #0, tick = 100000

Thread #1, tick = 50000

Thread #1, tick = 100000


Um sistema non-time slicing deixa que a thread fique sendo executada, até que ela deixe de requerer a CPU(dormindo,yield, finalizando o run()) ou se outra thread de prioridade maior chegar.

Note: A JRE não implementa(e também não garante) time-slicing. Entretanto, alguns Sistemas que você roda java tem suporte ao time-slicing. (Então OS SEUS PROGRAMAS EM JAVA NÃO DEVEM CONFIAR EM TIME-SLICING JA QUE CADA SISTEMA REPRODUZ UMA SAIDA DIFERENTE - por ter ou não time-slicing)

Como você deve imaginar, escrever código CPU-intensive pode ter repercussão negativa, em outras palavras em outras threads no mesmo processo. DE uma maneira geral, você deve tentar escrever threads "comportadas" que dão a chance de outras usar a CPU, ou seja de se tornarem RUNNING. VOCÊ NUNCA DEVE ESCREVER CÓDIGO QUE CONFIA EM TIME-SHARING - ISSO SO PRATICAMENTE GARANTE QUE O SEU PROGRAMA TERÁ DIFERENTES RESULTADOS EM DIFERENTES S.O.


Muitos programadores ficam surpresos quando aprendem que threads em java com mesma prioridade não dividem o tempo automaticamente por um escalonador(isso ocorre em processos - Round-Robin -).Parte dessa surpresa deriva da tendencia de pensar em threads dentro de um programa como um processo no S.O.: Isso tem sido coloca-do a nos que um escalonador de timeSlicing- é aquele que trabalha com múltiplos processos - NO S.O e falando em processos, isso é verdade.

Entretanto existem ocasiões em que o Round-Robin não é o que esta realmente disponível e fica a encargo do programador dividir o tempo entre as threads.


Vamos a um exemplo, supondo que temos um Servidor, esse servidor aceita conexões de socket, supondo que cada vez que um cliente se conecta ao servidor, sobe-se uma thread e é necessario fazer uma conta, que demora 5 segundos.

Prosseguindo temos 3 clientes se conectando ao servidor, lembrando são 5 segundos pela conta, vamos ver:(TODOS ESSES CASOS SÃO PARA UMA CPU SOMENTE)


- Com TimeSlicing, 3 clientes se conectam ao server, 3 cliente são processador ao mesmo tempo,(Vamos dizer que cada cliente é uma thread) então a CPU é dividida em 3, e temos a resposta aos 3 em ... 3 x 5 = 15 segundos, ou seja cada Cliente recebe a resposta da conta até os 15 segundos. O algortimo de Round-Robin pega o tempo total, 15 segundos e divide pelas threads.


- Sem TimeSlicing, 3 clientes se conectam ao server,1 cliente é processado por vez e quando terminar vai para outro, são criadas as 3 threads ao mesmo tempo, porem somente uma tem a possibilidade de ser processada e o resto fica aguardando enquanto o primeiro esta la, então a resposta para o primeiro pode ser em 5 segundos ao invés de 15(do Com TimeSlicing), ai entra o segundo cliente e ele ganha a resposta em 10(5 do primeiro + 5 do processamento dele) ao invés de 15, a do terceiro em 15...Existe uma ordem.


Qual é o melhor?

Dai depende doque você quer, veja:

- Se o servidor apenas fornece 1 resposta para o cliente, claramente o sem TimeSliced é mais justo: em media, cada cliente tem que esperar 10 segundos para uma resposta contra 15 segundos de um com timesliced.

- Com TimeSlicing, todos RECEBEM EM 15 segundos no máximo.

- Sem TimeSlicing, Primeiro em 5s, Segundo em 10s, Terceiro em 15 segundos.


***Lembre- se Time-slicing é um termo para que, o programa necessita da CPU por x tempo, esse tempo é dividido entre as threads do processo. ou seja THREAD A fica com 1/3, THREAD b fica com 1/3, THREAD c fica com 1/3...Só que, o tempo das threads é gasto por partes, Exemplo 10% do 1/3 do tempo ex:


Thread a usa 10% do 1/3 do tempo dela

Thread b usa 10% do 1/3 do tempo dela

Thread a usa 10% do 1/3 do tempo dela = ou seja ela ja usou 20%

Thread c usa 10% do 1/3 do tempo dela


E assim por diante, em S.O. Que usam a implementação do Round-Round acabam tendo esse TimeSlicing de tempo por thread. - Esse exemplo só é valido para o meu EXEMPLO.


- Se o servidor fornecer 5 respostas para os clientes, uma a cada segundo de conta , então o Sem timeSliced é mais justo: cada cliente tem a resposta(da conta) depois de no maximo 3 segundos(ou seja cada thread usa o timeSlicing dela.) - (isso ai invés de cada UM RECEBER EM 15 segundos que é oque acontece em com TimeSliced). (FALANDO EM QUESTÕES DE APENAS UMA CPU) - Ou seja o primeiro cliente recebe a primeira Mensagem no primeiro segundo, recebe a Segunda mensagem no segundo segundo etc.


- Com Time-slicing(Naquele conceito de fila)

(isso é só um exemplo, tem S.O. que trabalham com outro conceito de escalonamento)

EU SEI QUE NO TOTAL TEM QUE TER 15(3 threads x 5 segundos cada)


1 - Thread a usa uma parte to timeSlicing dela

2 - Thread b usa uma parte to timeSlicing dela

3 - Thread c usa uma parte to timeSlicing dela

4 - Thread a volta a usar o timeSlicing dela

5 - Thread b volta a usar o timeSlicing dela

6 - Thread c volta a usar o timeSlicing dela

7 - Thread a volta a usar o timeSlicing dela novamente

8 - Thread b volta a usar o timeSlicing dela novamente

9 - Thread c volta a usar o timeSlicing dela novamente

10 - Thread a volta a usar o timeSlicing dela novamente

11 - Thread b volta a usar o timeSlicing dela novamente

12 - Thread c volta a usar o timeSlicing dela novamente

13 - Thread a volta a usar o timeSlicing dela novamente

14 - Thread b volta a usar o timeSlicing dela novamente

15 - Thread c volta a usar o timeSlicing dela novamente


Supondo que cada segundo seja o timeSlicing das threads, cada cliente recebe a msg a cada SEGUNDO.

Em contra partida em non-timesliced , o terceiro cliente não terá sua primeira resposta ate se passar os 15 primeiros segundos. EX:


Thread A entra e envia todas as msg e termina em 5s

Thread B agora é Running entra e envia todas as msg e termina em 5s(5 de A + 5 de B = 10)

Thread C agora é Running entra e envia todas as msg e termina em 5s

(5 de A + 5 de B = 10 + 5 de C = 15 s)


Esta situação é mais complicada em um sistema com múltiplos CPUs, se nos temos 4 CPUS disponíveis para executar nossas 5 threads, então em um sistema que não faz timeSlicing(Sem timeSlicing), A media com que os cliente vão receber a mensagem é depois de 6 segundos:(Lembre-se cada thread demora 5s nesse caso)

1 - 5 s

2 - 5 s

3 - 5 s

4 - 5 s

5 - 10 s(pois tem que aguardar uma CPU, ou seja aguardo de uma 5, mais o tempo de processo + 5 = 10).


Por outro lado, se tivermos um sistema que envolva timeSlice a media sera : 6.2 segundos( (5 * 5) / 4 -> É a única conta que podemos afirmar). DE FATO PODEMOS DIZER QUE CADA CLIENTE TERA SUA MSG EM 6.2 SEGUNDOS. E SE TUDO QUE NOS IMPORTAMOS É O TEMPO FINAL, ENTÃO COM O timeSlice(e claro o algoritmo de Round-Robin) TEMOS 6.2 de métida X 6.0 de média sem TimeSlicing...Incluindo que o quinto cliente sem timeSlicing so receberá em 10, oque é muito diferente do resto, existe uma certa INIGUALDADE.


RESUMINDO se resultados intermediários são importantes, então Com Time-slicing é importante. Mais se nos preocupamos somente com o resultado final, então o Round-Robin e o TimeSlicing em uma simples CPU não é tao apropriado pois, não traz nenhum beneficio(ja em mais de uma CPU, temos uma certa certeza.).Todas atingem o objetivo, de maneiras diferentes.



Prioridades de Threads:


Grande parte dos computadores só tem uma CPU, e a troca de uma stack para outra é tão rápida que da aparência de Concorrência. A execução de múltiplas threads(Runnable) em uma simples CPU é chamado de escalonamento. A JRE suporta um simples algortimo de escalonamento nomeado: fixed priority scheduling. Ele praticamente se baseia na prioridade das threads em Runnable para serem Running.

Quando uma thread é criada, a thread herda a prioridade da thread que a criou. Você pode modificar a prioridade de uma thread a qualquer momento usando o setPriority().

AS prioridades das threads são valores inteiros que vão de MIN_PRIORITY ate MAX_PRIORITY (constantes definidas na classe Thread).Em um determinado modo quando o escalonador vê quais threads estão em runnable para se tornarem RUNNING ele escolhe aquela com mais alta prioridade e essa escolhida so sai desse estado apenas quando ela stop(),yield() ou tornasse Runnable por algum outro motivo, ou outra thread de prioridade maior quer se torna RUNNING.


Se duas threads de mesma prioridade estão disputando pela CPU, o escalonador escolherá uma para rodar no estilo round-robin(Ou seja aquele que vê elas como lista, ai coloca a primeira, tira e fica maior troca troca de thread), NA MAIORIA DOS S.O. E das implementações da JVM CLARO, pois ele pode muito bem deixar um entrar em RUNNING e pronto, ai entra a “manipulação” do programador.


Até quando uma thread ficará rodando? condições:


* Uma thread de prioridade maior entre na historia

* yield() seja invocado, stop(), ou run() termine o code_bloc

* Ou em um sistema que suporte time-slicing diga que o tempo de uso terminou.


O algoritmo de escalonamento de threads as vê como obtenção. Se em um determinado momento, uma thread com maior prioridade se torna RUNNABLE e a thread que estiver RUNNING for de menor prioridade , a thread de MAIOR PRIORIDADE OBTEM O ESTADO DE RUNNING(NO CASO SO TEMOS UMA CPU, ENTÃO A THREAD QUE PODE AGORA É A DE MAIOR PRIORIDADE, UMA CPU POR THREAD.).



TEMOS 3 CONSTANTES NA CLASSE DE THREAD QUE DEFINEM AS PRIORIDADES:


Thread.MIN_PRIORITY - O minimo que uma thread pode ter - 1 -

Thread.MAX_PRIORITY - O maximo que uma thread pode ter - 5 -

Thread.NORM_PRIORITY - O normal a uma thread - 10 -


***LEMBRE-SE TODA THREAD VEM DE UMA THREAD GROUP, ENTÃO ELAS SEGUE AS PRIORIDADES DO THREAD GROUP, PRINCIPALMENTE EM QUESTÕES DE PRIORIDADE O RANGE PODE MUDAR MUITO.


Algumas Jvm, deixam você configurar a prioridade de uma thread como 0.


Temos 2 métodos para agir com prioridades:


void setPriority(int priority)


int getPriority()



*** MUITO BOM PARA USAR, É QUANDO SE USA CPU INTENSIVE COM Interactive OU I/O INTESIVE, QUER DIZER UMA THREAD FICA FAZENDO AS COISAS, E OUTRAS ESPERANDO(UMA ENTRADA DE USUARIO E TAL) E A THREAD QUE FICA FAZENDO AS COISAS É CONFIGURADA PARA UMA PRIORIDADE MENOR, OU SEJA QUANDO ACONTECER OQUE QUEREMOS...A THREAD DE INTERACTIVE OU I/O SAEM DO ESTADO DE BLOCKED, e se tornam running, pois tem maior prioridade.


Quando configurar a prioridade de threads é importante?

- Quando temos apenas uma CPU intensive thread(ou uma CPU somente na máquina)

- resultados intermediários são importantes


Oque são resultados intermediários?

Ex: Temos uma thread CPU intensive(que tem um loop, que faz contas e a cada loop ele mostra para o user o resultado) e temos um thread Interactive(que fica esperando uma ação do usuário, claro temos que fazer os 2 ao mesmo tempo), então a thread que é CPU intensive ao fazer uma conta, mostra para o user o resultado(so que ela faz essa conta "n" vezes), porem cada resultado é importante, não somente o resultado final... na 1x que faz a conta sai o resultado para o user, na 2x que faz a conta sai o resultado para o user, na 3x que faz a conta sai o resultado para o user e assim por vez... Isso enquanto a thread de INTERACTIVE não recebeu nenhum evento...isso que é chamado de resultado intermediário.


Próxima seção resumo !!!

CYA DUDES!!!

Um comentário:

  1. Olá amigo, curti muito essa postagem! Eu estou querendo implementar um escalonador de prioridades com threads, em que o usuário diz quantas threads ele quer e elas só fazem printar na tela uma mensagem, mas conheço pouco do java. Teria como você me dar umas dicas? Desde de já agradeço!!

    ResponderExcluir