terça-feira, 25 de agosto de 2009

Entendendo Threads 02:

Sumário: Pacotes básicos, Criando threads, estados básicos de threads, métodos básicos para manipulação de threads

PACOTES Básicos:

java.util.concurrent;

java.lang.Thread;

java.lang.Runnable;


Como eu crio um Objeto thread?

Leva-se em consideração que em java, quase tudo é um objeto. Portanto como eu crio um objeto thread? Olha que legal, você tem a possibilidade de criar um objeto que é um Stack. É Realmente a abstração faz milagres. Temos 2 maneiras básicas:


*Princípio Básico do tutorial, TODA THREAD PRECISA DE UM MÉTODO QUE É OQUE VAI NO FUNDO DA STACK. NO NOSSO CASO É O run().

A classe Thread , se encontra no pacote default de todo processo em java, java.lang.Thread; - Verifique que o método main() é aquele que vai no fim da Stack que é criada por uma instancia da JVM, quando start() nossa thread, inciaremos outra STACK, e o run() é qual vai no fim da nossa nova STACK. Temos aqui 2 Stacks, uma com main(), outra com run().

1 – Declare uma Classe que extends Thread e implemente o run()

public class MyThread extends Thread{

public void run(){


}//end of run()

public static void main(String array[]){

(new MyThread()).start();


}//end of main

}//end of MyThread

2 – Nessa segunda maneira veremos uma thread como se fosse um Worker. Sendo assim toda thread precisa de um Job. Todo trabalhador precisa de um emprego certo?

Um objeto Runnable(java.lang.Runnable) será nosso emprego, lembre-se Runnable é uma interface.

***Perceba a classe Thread é um Runnable também

2.1 - Declare uma Classe que implements Runnable
2.2 – Instancie essa classe(no nosso caso MyJob), até ai só temos o emprego, precisamos de quem executa esse emprego.
2.3 – Instancie uma Thread e passe como parâmetros referentes aos argumentos do construtor o emprego que esse trabalhador terá.


public class MyJob implements Runnable{ //2.1


public void run(){


}//end of run()


public static void main(String [] array){

MyJob job = new MyJob(); //2.2

Thread worker = new Thread(job); //2.3

worker.start();


}//end of main()

}//end of Runnable


Em ambos os casos eu acabei de criar isso:

Clique na figura para maximizar


Qual a diferença entre somente instanciar uma Thread e instanciar uma Thread e invocar start() dessa instancia?

Quando você instancia uma nova thread – MyThread my = new MyThread() - , você só tem um objeto thread, e esse objeto thread se encontra no estado New, Você ainda não tem oque mais quer, que é a Stack dessa thread, com o run() no fim da Stack.

Quando você instancia uma nova thread – MyThread my = new MyThread() - , e logo após inicializa ela – my.start() - Você deixa sua thread nomeada “my” no Estado Runnable.(Isso não significa que a thread foi iniciada,). Existe uma dependência que é a seguinte,

1 – Precisamos que o escalonador do S.O. esteja disponibilizando a CPU para a thread em questão.

2 – Precisamos que o escalonador de java esteja disponibilizando também a CPU para a criação dessa thread(isso dependerá do estado de outras threads.)

Se a thread passar em ambas as dependências acima, o run() será o primeiro frame criado na Stack da thread, ou seja é o primeiro método a ser executado e o ultimo a ser terminado. - Ai sim teremos uma thread no estado RUNNING.

Em anexo a ilustração:

Isso é somente a Operand STACK e HEAP da Thread main(A Stack referenciada aqui é a Operand STACK da STACK ), muito diferente de termos 2 stacks, como mais acima em "Em ambos os casos eu acabei de criar isso:" está.


Pontos positivos e Negativos de se usar extends Thread ou, criar um objeto Runnable e passar como parâmetros a outro objeto Thread: - (Basicamente tudo depende da Necessidade)-


Usando extends Thread:

Positivos:

1 – A implementação é bem mais fácil

Negativos:

1 – Em java só temos Herança simples ou seja, se você usar extends Thread, a sua classe não poderá ser mais nada alem de uma thread.

2 – Não é uma boa pratica da visão de O.O, a mesma classe seria um Trabalhador e um Trabalho.

Implementando a Interface Runnable:

Positivos:

1 – Em O.O a idéia é que cada parte tenha sua função, ou seja, temos um Objeto que é a thread em si, e temos um objeto que fará o trabalho da thread.

2 – Temos a possibilidade de Herança. Runnable é uma interface eu ainda posso implementar “n” outras interfaces.

Negativos:

1 – É mais trabalhoso.


Métodos Básicos de Manipulação de threads:


Pausando a Execução temporária de uma thread:


static sleep() - Causa a Suspensão da Execução daquela thread por um determinado período. (Simplesmente pausa a execução da Stack que esta em Runtime).Isso é realmente Significativo para o Tempo que o processador disponibiliza para outras threads ou para outros aplicativos que possam estar vindo a ser Executados no S.O.


Temos dois tipos de métodos Thread.sleep():

1- Onde você especifica o tempo em milissegundos

2-Onde você especifica o tempo em nanosegundos.


Cuidado ao usar o sleep() que se especifica em nanoSegundos porque nem todas as JVM dão suporte.


Quando eu invoco Thread.sleep() na thread em Runtime, qual será o estado dela?

Se uma thread esta em Runtime, o estado dela é Running, quando o pc do PC Register chega na instrução na Method Area que diz: Thread.sleep() (Claro em bytecode) o ESTADO DA thread passa de RUNNING para Blocked(ou seja temporariamente não RUNNABLE)


Quando terminar o tempo especificado na Thread.sleep(long time) oque acontece com o estado da Thread?

Uma thread que se encontra no estado Bloqueado quando termina o time definido no método, a thread passa do estado DE BLOCKED para o estado RUNNABLE, ficara a encargo do escalonador do S.O. E do escalonador de java saberem quando ela poderá entrar no estado RUNNING de novo.(Esses detalhes sobre oque o escalonador do S.O. E de java verão é visto acima nesse tutorial em qual a diferença de um objeto thread e um objeto thread.start()).

Thread.sleep() dá uma chance as threads de prioridade mais baixa de se tornarem RUNNING. O Thread.yield() dá a chance de outras threads se tornarem de RUNNABLE para RUNNING.


Terminando prematuramente uma thread:


void stop() - Uma thread termina o seu ciclo quando termina o metodo run(), o metodo stop() simplesmente faz a thread terminar o run() prematuramente.

Nunca restaure um thread, não é usual ficar fazendo start(), stop() na maioria das vezes nem funciona... Uma vez a thread Dead, ja era .


Métodos para ciclos de vida de uma thread:

Verificando se uma thread ainda pode ser usada:


boolean isAlive() - isAlive() avalia somente 2 coisas.

1- Se a thread.start() já foi invocado

2- Se o run() ja terminou o code_block dele

Ou seja se a thread esta no espaço de tempo entre o inicio e o fim do ciclo da vida dela. O isAlive() também avalia se o stop() foi chamado, já que o método stop() termina o run() prematuramente significando também o fim do ciclo de vida de uma thread.

LEMBRE-SE, existe um espaço de tempo entre você invocar o start() e a thread realmente se tornar Runnable, e também existe um espaço de tempo entre o termino do run() ou a invocação de stop() e realmente a thread terminar seu code_block, dependêrá dos escalonadores(DO S.O e de java) – (ou seja para ela entrar no ESTADO DEAD)-

Resumindo: isAlive() retorna true para a thread que já foi iniciada(start() ) e que ainda não terminou o code_block dela(ou seja não esta no estado DEAD).

Retorno: É boolean e retorna true se,a thread estiver ALIVE, oque é estar ALIVE? É quando a thread esta em Runnable(ou seja já invocarão start() nela) e a mesma ainda não terminou seu code_block(ou seja não esta em DEAD).


Fazendo com que uma thread aguarde outra terminar o code_block:


Join(ingressar, associar-se, unir) -

FAZ COM QUE UMA THREAD ESPERE PELO TERMINO DE UMA OUTRA,(OU pelo tempo especificado nos parâmetros ao método, OU até que a thread que foi feita a chamada termine o code_block dela).

Assim como sleep(), join lança uma InterruptedException.


Como usar o void join()?

Especificando no código da thread que você quer que aguarde ....Dentro da thread que você quer que aguarde , você chamada o método com a referencia a thread que se tornará RUNNING.


Dando nome as threads:

void setName(String name) - É usado mais para debug, quando acontecer um erro você sabe onde é, ou para imprimir toString(). Por Default se a thread não tiver nome fica "Thread - " depois do “-” temos o numero dela...

ex: "Thread – 0"
String getName() -
Captura o nome da thread.


ACESSANDO threads, já pensou em como capturar a thread de main?


static Thread currentThread() - Retorna um endereço de memoria referente ao objeto thread que esta em RUNTIME no momento.(ou seja é a thread que chamou Thread.currentThread() .) esse é o único método capaz de realmente retornar um endereço de memoria referente a uma thread.



Capturando todas as threads ativas no seu Programa:


static int activeCount() - Me retorna o numero de threads ativas no meu Programa(Normalmente é usado para saber o length da array usada pelo método enumerate(Thread [] array)).

Na definição do isAlive() uma thread é considerada "Ativa" se ela já foi start() e se ainda não terminou o code_block do metodo run()(ou se não foi invocado stop()). Na visão do activeCount() temos uma diferença que é a seguinte, uma thread é considerada "Ativa" quando a thread foi construída e não apenas .start()(ou seja quando temos a instancia), e ela não é considerada "Ativa" ou quando o método run() terminou ou quando invocarão stop() nela.

static int enumerate(Thread threadArray[]) - retorna um inteiro dizendo o length da array, e a array que for passada como Parâmetro(ao argumento do método - Thread threadArray[] - ), recebe referencias ao objetos Thread que estiverem ativos atualmente no Programa. Ou seja ao invocar o método, passe como parâmetros aos argumentos do método, um array, o metodo me retornará o length da array, alem da array que passei como parâmetros voltar com referencias as threads atualmente ativas no programa.


Dando a chance a threads Runnable serem Running:


static void yield() -Tira a thread onde for invocado do estado de Running
para
Runnable, e se outras threads estiverem no estado Runnable, elas agora
tem a
chance de serem RUNNING. Thread.sleep() dá uma chance as threads de
prioridade mais baixa a se tornarem RUNNING. O Thread.yield() dá a chance
de outras threads de mesma prioridade de se tornarem de RUNNABLE
para RUNNING.


Resumão:

- Quando você somente instancia um objeto thread, você obtêm uma thread no estado NEW.

- Quando você invoca start() em um objeto thread, ele passa do estado NEW, para o estado RUNNABLE porem ele ainda pode não estar pronto para ser RUNNING, dependerá do Escalonador do S.O. E o Escalonador de java, passando em ambas dependências o Escalonador java cria a Stack referente a thread, e o run() sera a primeira frame criada na STACK.

- Todas as threads que estão em RUNNABLE, são mantidas em um Pool de Runnables.

- Uma thread termina o seu ciclo de vida, quando termina o run(), ou seja o método que fica no fim da Stack, Stack sem frames = Stack que não existe mais.

- Se usar a Interface Runnable para implementar a criação de threads, e precisar na thread de referências de objetos, PASSE COMO PARAMETROS referentes ao construtor da Classe que implements Runnable as Referencias

MyRunnable job = new MyRunnable(myReferenceVariable);

Thread worker = new Thread(job);


- o static sleep(), Coloca a thread em Runtime em pausa(A thread em runtime passa do estado RUNNING para BLOCKED), dando assim oportunidade para outras threads entrarem no estado RUNNING, É uma boa pratica colocar threads em estado BLOCKED em curtos tempos como 50 ms, apenas para dar a chance a outras.


- Não restaure threads fazendo start(), stop(), isso realmente não é muito funcional

- Existe um espaço de tempo entre você invocar o start() e a thread realmente se tornar Runnable e também existe um espaço de tempo entre o termino do run() ou a invocação de stop() e realmente a thread terminar seu code_block(ou seja se torna DEAD), dependerá dos escalonadores(DO S.O e de java).

- Não faz sentido usarmos isAlive() e join() na própria thread. Porque você sabe quando ela esta viva ou não. e o join() retorna quando a thread não esta mais Alive, ou seja...Se você usar no code_block de uma thread que esta Alive, quando ela não vai estar se eu to esperando nela mesma?


- Thread.sleep() dá uma chance as threads de prioridade mais baixa a de se tornarem RUNNING. O Thread.yield() dá a chance de outras threads de mesma prioridade se tornarem RUNNING.

- Quem seleciona se uma thread deve ou não estar Running, é um jogo entre, o escalonador do S.O, o escalonador de java, e sua “manipulação” nesse meio.

- A classe Threadé uma Runnable(Herança, implements Runnable).



Estados threads:

- New – Quando o objeto thread é criado, porem não invocaram o start() na referencia.

- Runnable – Quando volta de algum estado, ou quando foi invocado o start() na referencia e o objeto aguarda a chance de se tornar RUNNING.

- Running – A thread esta sendo executada sobre o controle da CPU

- Dead – Quando a thread terminou o code_block do run(), ou seja quando não temos nenhum frame referente a Stack dessa thread. - (ou quando foi invocado o stop() )-


BLOCKED –

1 – Thread.sleep() - Passa a thread de Running para Blocked, depois de Blocked ele volta a ser Runnable.

2 – Uma thread é considerada no estado BLOCKED quando esta esperando dados .(Ou seja ela não pode estar no estado RUNNING, pois esta esperando que algo ocorra), exemplo uma thread esperando InputStream do Socket dela.

3 – Uma thread tambem é considerada BLOCKED quando esta aguardando a Lock de outra thread.



Bom em Básico 02 é so isso, já é um básico nível intermediário

CYA DUDES!

Nenhum comentário:

Postar um comentário