Dúvidas com Interação entre Threads

Olá pessoal do GUJ
Li alguns tópicos sobre Interação aqui mas não achei uma resposta para a minha pergunta! Bem ai Vai!

Tenho o Seguinte Código(como podem ver eu estava brincando com ele um Pouco):

public class Duvidas {
   
         
    public static void main(String args[]) {  
      Other o = new Other();
      o.setName("-A-");
      Other oo = new Other();
      oo.setName("-AA-");
     
      o.start();
     oo.start();
      synchronized(o){
          try{
            System.out.println("waiting for O ...");
            o.wait();
            System.out.println("O is OK ...");
          }catch(InterruptedException e){
            System.out.println("Total: " + o.total);
          }
      }
    
     synchronized(oo){
          try{
            System.out.println("waiting for OO ...");
            oo.wait();
            System.out.println("OO is OK ...");
          }catch(InterruptedException e){
            System.out.println("Total: " + oo.total);
          }
      } 
              
   }
     
}

class Other extends Thread{
    int total;
    public void run(){
        synchronized(this){
            System.out.println("Inicio" +Other.currentThread().getName());
            for(int i = 0; i < 10 ; i++){
                try {
                    sleep(400);
                    System.out.println("Run: "+i+" "+Other.currentThread().getName());
                    total += i;
               }catch (InterruptedException ex) {
                    System.out.println(ex);
                }
            }
            notifyAll();
        }
    }

}

Com a Saida(Não Garantida é Claro):

run:

waiting for O … //Ok! entrei no Bloco Synchronyzed
Inicio-A- //OK! Entrei em run() com a Thread "o"
Inicio-AA- //OPA! Como assim? run() Sem Entrar no Bloco Synchronyzed de "oo"
Run: 0 -A-
Run: 0 -AA-
Run: 1 -AA-
Run: 1 -A-
Run: 2 -AA-
Run: 2 -A-
Run: 3 -AA-
Run: 3 -A-
Run: 4 -AA-
Run: 4 -A-
Run: 5 -AA-
Run: 5 -A-
Run: 6 -AA-
Run: 6 -A-
Run: 7 -AA-
Run: 7 -A-
Run: 8 -AA-
Run: 8 -A-
Run: 9 -AA-
Run: 9 -A-
O is OK …
waiting for OO … // Agora que ele vai querer aguardar! e o programa nunca termina!

Bem eu sei que pra poder ter a garantia(que não é verdade pois o agendador é imprevisível) de uma saida uniforme eu preciso sincronizar a classe (Ex: synchronized(Other.class) ), mas não entendo por que quando a 2ª thread “Starta” ela só procura o bloco sincronizado quando termina de rodar(run())?
para deixar mais claro gostaria de saber por que não tenho uma saida mais ou menos assim:


run:

waiting for O … // Entra no Bloco Sincronizado depois em run() …
waiting for OO … // Deixa da rebeldia e também entra no bloco sincronizado antes de entrar em run().
Inicio-A-
Inicio-AA-
Run: 0 -A-
Run: 0 -AA-
Run: 1 -AA-
Run: 1 -A-
Run: 2 -AA-
Run: 2 -A-
Run: 3 -AA-
Run: 3 -A-
Run: 4 -AA-
Run: 4 -A-
Run: 5 -AA-
Run: 5 -A-
Run: 6 -AA-
Run: 6 -A-
Run: 7 -AA-
Run: 7 -A-
Run: 8 -AA-
Run: 8 -A-
Run: 9 -AA-
Run: 9 -A-
O is OK …
OO is OK …

Resumo do resumo

Por que a 2ª thread não faz como a primeira (o -> sync() -> run()) e pula logo pra segunda(oo -| sync() -> run())

Não sei se fui claro, mas caso não avisa ai que eu tento explicar de maneira mais detalhada.

Contudo Agradeço dês de já!

Dependendo da ordem que as operações forem executadas, o método notifyAll pode ser executado antes do wait, por isso que o programa trava, pois ele irá esperar um notifyAll que nunca ocorrerá (já que ele já ocorreu em um momento anterior). Pra testar isso, eu modifiquei o código da seguinte forma:

package teste.concorrencia;

public class Duvidas {
	   
    
    public static void main(String args[]) throws InterruptedException {  
      Other o = new Other();
      o.setName("-A-");
      Other oo = new Other();
      oo.setName("-AA-");
     
      o.start();
     oo.start();
     
      synchronized(o){
          try{
            System.out.println("waiting for O ... Já executou o notifyAll? " + o.isJaExecuteiONotify());
            o.wait();
            System.out.println("O is OK ...");
          }catch(InterruptedException e){
            System.out.println("Total: " + o.total);
          }
      }
    
     synchronized(oo){
          try{
            System.out.println("waiting for OO ... Já executou o notifyAll? " + oo.isJaExecuteiONotify());
            oo.wait();
            System.out.println("OO is OK ...");
          }catch(InterruptedException e){
            System.out.println("Total: " + oo.total);
          }
      }
     
              
   }
     
}

class Other extends Thread{
    int total;
    private volatile boolean jaExecuteiONotify;
    
    public boolean isJaExecuteiONotify() {
    	return jaExecuteiONotify;
    }
    
    public void run(){
        synchronized(this){
            System.out.println("Inicio" +Other.currentThread().getName());
            for(int i = 0; i < 10 ; i++){
                try {
                    sleep(400);
                    System.out.println("Run: "+i+" "+Other.currentThread().getName());
                    total += i;
               }catch (InterruptedException ex) {
                    System.out.println(ex);
                }
            }
            notifyAll();
            jaExecuteiONotify = true;
        }
    }

}

Executa esse código novo e verá que na linha em que o código trava será exibido que a thread já executou o notifyAll antes do wait…

Se o seu objetivo é aguardar a execução das threads o melhor é utilizar o método join:

package teste.concorrencia;

public class Duvidas {
	   
    
    public static void main(String args[]) throws InterruptedException {  
      Other o = new Other();
      o.setName("-A-");
      Other oo = new Other();
      oo.setName("-AA-");
     
      o.start();
     oo.start();
     
     /* 
     synchronized(o){
          try{
            System.out.println("waiting for O ... Já executou o notifyAll? " + o.isJaExecuteiONotify());
            o.wait();
            System.out.println("O is OK ...");
          }catch(InterruptedException e){
            System.out.println("Total: " + o.total);
          }
      }
    
     synchronized(oo){
          try{
            System.out.println("waiting for OO ... Já executou o notifyAll? " + oo.isJaExecuteiONotify());
            oo.wait();
            System.out.println("OO is OK ...");
          }catch(InterruptedException e){
            System.out.println("Total: " + oo.total);
          }
      }*/
     
              
     o.join();
     System.out.println("O is OK ...");
     
     oo.join();
     System.out.println("OO is OK ...");

     
   }
     
}

class Other extends Thread{
    int total;
    private volatile boolean jaExecuteiONotify;
    
    public boolean isJaExecuteiONotify() {
    	return jaExecuteiONotify;
    }
    
    public void run(){
        synchronized(this){
            System.out.println("Inicio" +Other.currentThread().getName());
            for(int i = 0; i < 10 ; i++){
                try {
                    sleep(400);
                    System.out.println("Run: "+i+" "+Other.currentThread().getName());
                    total += i;
               }catch (InterruptedException ex) {
                    System.out.println(ex);
                }
            }
            notifyAll();
            jaExecuteiONotify = true;
        }
    }

}

Pow Obrigado, já havia percebido, mas gostaria de saber por que as duas threads não entram no primeiro Bloco Sincronizado(Somente a 1ª thread entra nos dois a segunda não)

Já percebeu que os métodos wait(), notify() e notifyAll() são métodos da classe Object, e não da classe Thread ?

Já percebeu que os métodos wait(), notify() e notifyAll() são métodos da classe Object, e não da classe Thread ?[/quote]

Hum … tava olhando o Código do Amigo rogeriopaguilar usando Wait() e sei que tem o comportamento que eu espero que tenha(por falar nisso belo código!) … Sabia sim que esses métodos são da CLasse Object, e que eu não tinha ligado o Nome a Pessoa … Então só tem esse comportamento devido isso? por serem da classe Object? eu ainda estou meio que me enrolando com Bloqueio e desbloqueio … com a ajuda de vocês eu estou quase entendendo mas ainda está meio nebuloso … Obrigado pela Atenção!

Já percebeu que os métodos wait(), notify() e notifyAll() são métodos da classe Object, e não da classe Thread ?[/quote]

Hum … tava olhando o Código do Amigo rogeriopaguilar usando Wait() e sei que tem o comportamento que eu espero que tenha(por falar nisso belo código!) … Sabia sim que esses métodos são da CLasse Object, e que eu não tinha ligado o Nome a Pessoa … Então só tem esse comportamento devido isso? por serem da classe Object? eu ainda estou meio que me enrolando com Bloqueio e desbloqueio … com a ajuda de vocês eu estou quase entendendo mas ainda está meio nebuloso … Obrigado pela Atenção![/quote]

É que a impressão que eu tive, é que talvez você esteja confundindo as coisas. Bom, se o método wait() pertence à classe Object, concorda comigo que ele pode ser chamado a partir de qualquer objeto, e não apenas de Threads correto ?
Pois bem, ocorre que chamando o método wait() você bloqueia a thread corrente, e não o objeto. No seu caso, quando você chama o.wait() ou oo.wait() você bloqueia a thread principal, e não as threads o e oo. Provavelmente acontece que a thread oo termina antes da thread principal chamar wait() e é encerrada, de forma que não sobra ninguém para chamar notifyAll() e destravar a thread principal.

Hum … Agora Sim as Coisas fazem sentido!!! OK era exatamente isso que eu queria entender … Valeuzão a todo pessoal do GUJ em especial ao companheiro rogeriopaguilar, que me deu a resposta, mas eu não consegui enxergar por não conhecimento e o companheiro rmendes08 que teve paciência de me ajudar a enxergar com mais clareza o que tava na minha cara hahahahaha … estou a 1 semana da prova e tenho tido bons resultados (Para quem saiu da inércia total) mas ainda apanho um pouco para Threads, continuarei com os estudos … Bem … Mais uma vez Obrigado e até um Próxima!

Olá conforme vc falou : [quote]
Pois bem, ocorre que chamando o método wait() você bloqueia a thread corrente, e não o objeto. No seu caso, quando você chama o.wait() ou oo.wait() você bloqueia a thread principal, e não as threads o e oo. Provavelmente acontece que a thread oo termina antes da thread principal chamar wait() e é encerrada, de forma que não sobra ninguém para chamar notifyAll() e destravar a thread principal. [/quote]

ola so queria q esclarecessem uma duvida que eu fiquei o primeiro bloco synchronized (o) bloqueia a thread “o” que fica esperando um notify .
(duvida)qual thread ela bloqueia a main ou a thread “o”?
Aqui em ksa nao houve bloqueio das threads durante a execução do run() só depois delas terem terminado, e portanto o código não avança nem para o segundo synchronized (oo) e a última mensagem é waiting for o… (ficou no primeiro synchronized a thread main) que provavelmente está (estão ) morta(as), então o synchronized dentro do run() nao funcionou muito pois ele teria que bloquear a thread até ela terminar… ou ele não garante isso ?

ok, acho q já entendi segundo a penúltima explicação postada nesse tópico . Então como fazer esse código (se é que é possível ) funcionar com wait() e notify() ? Mantendo as duas threads , só que uma avisa a outra que já acabou através do notify … :PPPP acho nem sei o q tou falando … queria saber primeiro o objeto desta classe Duvida , será que é o mesmo objetivo que eu estou pensando (o de funcionar duas threads concorrentemente através do notify)? ou tás brincando de deadlock??

Abraços