Dúvida em run() e start()

Vini se o t.run() chama o método run de Thread e nao da Threads3 quando ele da t.run(), não era pra exibir nada ou era?

Era, veja a implementação do run() de Thread, que coloquei um pouco abaixo.

Aquele target do método run significa o que?

É o runnable que você passou por parâmetro. Ele será null caso você use o construtor default.

ahhh sim perfeito, etendido então ehehe, ai sim ele chamaria os dois run() da classe Threads3 :slight_smile:

[quote]não faz o menor sentido.

Pelas regras, deve sempre ser escrito running três vezes. Não existe isso de que se uma thread morrer os comandos após a chamada dessa thread não serem executados. Tudo sempre é executado, a não ser que haja um comando como esse na main [/quote]

nossa foi mal então, thread pode executar os comandos rsrsrs , nunca kra!
Que regras rsrsrs ve primeiro a API antes de falar o que não sabe.

Faz o seguinte, põe o sleep depois do start e um throws Exception no main e vcs nunca mais verão 3 mensagens na tela. Não há problema nenhum na JVM.

[code]public class Threads3 implements Runnable{
public void run(){
System.out.println(“running”);
}

 public static void main (String args[]) throws Exception {  
     Thread t = new Thread( new Threads3() );  

     t.start();  
     Thread.sleep(1000);
     t.run();  
     t.run();  
 }  

} [/code]

[quote=Will_HRock][quote]não faz o menor sentido.

Pelas regras, deve sempre ser escrito running três vezes. Não existe isso de que se uma thread morrer os comandos após a chamada dessa thread não serem executados. Tudo sempre é executado, a não ser que haja um comando como esse na main [/quote]

nossa foi mal então, thread pode executar os comandos rsrsrs , nunca kra!
Que regras rsrsrs ve primeiro a API antes de falar o que não sabe.[/quote]

Rapaz… chega a ser frustrante ler isso de alguem que tem certificação.

Então façamos threads sem comandos, pra quê? Não sei, talvez a sua API e sua certificação digam.

Testa o código com o sleep e me fala porque aparece só uma vez então

Tem razão, após o fim da execução da thread, ele limpa o target.

É bom lembrar que esse programa aí possui 2 threads. A main thread, que executa o método run() duas vezes, e a thread disparada pela classe Thread.

O que acontece é que a thread disparada pela classe Thread limpa o runnable interno, assim que finaliza. Quando a main thread chama o método run, esse não fará nada, já que o target estará nulo.

Mas não tem nada a ver com o estado Terminated, até porque, a thread que está chamando run() diretamente é a main thread, que ainda não finalizou sua execução.

Isso é uma característica da implementação da classe Thread. Tanto, que por sobrescrita do método run, funciona, mesmo com o sleep:

[code]
public class Teste implements Runnable {
public void run(){
System.out.println(“running”);
}
public static void main (String args[]) throws Exception{
Thread t = new Thread() {
@Override
public void run() {
new Teste().run();
}
};

  t.start();
  Thread.sleep(1000);
  t.run();
  t.run();

}
}[/code]

Se vc reler o que eu escrevi primeiramente eu disse que não deveria haver nenhum sleep ou setDaemon na thread em que o método main está…
ok?

Não achei você falando de sleep

Há algo de maquiavélico nessa questão, e duvido que algo assim caia na certificação. Ela está fortemente atrelada a como a classe Thread foi implementada, não tanto no funcionamento das threads em si.

Por exemplo, quem chama run() duas vezes é a main Thread. Você, a principio, não deveria se preocupar com o estado terminated, pois você não está tentanto reiniciar thread nenhuma. Compartilhar código é algo natural entre threads, e por isso a maioria imaginou que aquele código fosse imprimir normalmente.

Mas, a questão é que a classe Thread limpa seu runnable interno, e isso é o detalhe maldoso. A única invariante que a classe Thread conceitualmente deveria garantir é não ser reiniciada, caso atinja o estado de TERMINATED, não que outra thread possa re-executar seu runnable interno.

Aliás, esse compotamento me supreendeu. Uma construção java válida, que não dará erro, mas resultará em comportamento inconsistente é essa aqui:

Thread t = new Thread(umRunnable); t.start(); t.join(); new Thread(t).start();

Porém, se t tiver terminado, não haverá erro, e o código também não fará nada. Note que não estou reutilizando threads, mas criando uma nova.

Ok, a maior parte desses códigos para certificações são mesmo abominações e esse é um deles. Mas, justamente ser dependente de implementação, e não de conceitos, é que acho que ele não deverá cair numa certificação no futuro.

Qualquer modificação no código em geral.

Até porque eu estava respondendo a questão do nosso amigo, cujo problema não tinha nem sleep, nem wait nem qualquer outra coisa do tipo.

Entendeu agora ou vai continuar se fazendo de mal entendido?

Parei, não quero discutir, só achei ruim quando você achou um absurdo o que eu tinha falado.

Resolvi ler o código fonte da classe Thread, e me deparei com um comentário que dizia que a thread limpava o seu runnable no exit por causa do bug 4006245.

private void exit() {
   if (group != null) {
      group.remove(this);
      group = null;
   }
   /* Aggressively null out all reference fields: see bug 4006245 */
   target = null;
   /* Speed the release of some of these resources */
   threadLocals = null;
   inheritableThreadLocals = null;
   inheritedAccessControlContext = null;
   blocker = null;
   uncaughtExceptionHandler = null;
}

O link para o bug está aqui:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4006245

A razão pela qual isso foi implementado é puramente performance. Se o objeto Thread permanecer vivo com a referência ao Runnable, este Runnable poderá demorar mais a ser coletado. Portanto, foi solicitado que o runnable fosse limpo ao final da execução da thread. Note que, novamente, esse comportamento está mais relacionado a um detalhe de implementação, não ao conceito de como threads funcionam.

Conceitualmente, seria correto esperar que o código se comportasse como imaginamos, imprimindo running 3 vezes. Porém, graças a essa otimização, isso não irá ocorrer quando a Thread finalizar.

Hum, deixa ver se eu entendi. Para mim, esse código deveria escrever o “Running” somente uma vez pois o objeto t da classe Thread não implementa o run(), mas sim somente a classe Threads3, cujo método run() é chamado através do método start(). Mas, de acordo com a API, enquanto a thread nova criada estiver “viva”, se você chamar o método run() do objeto da classe Thread, ele na verdade então chamará o run() do objeto Runnable atrelado a ele, é isso?
E no caso do código do Tiago, as vezes ocorria de escrever “Running” uma vez e outras 3 vezes porque a Thread “morria” antes de se escrever os outros “Running” restantes??

Isso. Veja a implementação do método run(), um pouco atrás. E veja também o detalhe ele limpar o runnable após a morte da thread.

Isso mesmo.

ViniGodoy, então aquele meu código inicial, lá do primeiro post, poderia imprimir apenas 2 vezes “running” também não? Veja:

  1. t.start() é iniciado, mas não executa o método run(). O controle volta pra main.
  2. A main executa o primeiro t.run(), imprimindo “running”.
  3. O controle volta pra thread t, onde o run() é executado, imprimindo “running” novamente. Agora, por causa daquela otimização da implementação da classe Thread, ele marca a referência target (que tinha meu Runnable) para null. O código, então, volta para a main.
  4. Na main, executa mais uma vez o t.run(). Agora, porém, o target é null e vai ser usada a implementação run() da classe Thread (que não faz nada, tem apenas um corpo fechado).

Ou seja, acabou imprimindo apenas 2 vezes! Pode acontecer isso? Eu fiz centenas de testes aqui e sempre imprimi 1 ou 3 vezes, mas acho que também existe essa possibilidade de imprimir 2 vezes…

Obrigado! :slight_smile:

Existe sim. Se não ocorreu, é pq provavelmente o seu escalonador não deixará uma thread rodando por tão pouco tempo no processador.

Mas isso não significa que outro micro (como um dual ou quad core) ou um outro SO não faça isso.

Aliás, esse é o inferno das aplicações multi-thread. Você tem sempre a chance daquele bug que aparece uma vez a cada 3 meses e apenas na máquina do seu cliente.