Como esperar uma thread parar?

Pessoal,

Eu tenho na minha aplicação a instancia de um objeto no qual seu contrutor tem um thread iniciada e rodando,queria saber como faço pra que minha aplicação espere a Thread desse objeto finalizar pra então exibir o resultado dela?
Tentei com “synchronized” mas não deu certo da maneira que eu quero,alguem tem uma sugestão de codigo?

Olá!

Como vc deve saber, toda operação de sincronismo é feita com referência a um lock.

Toda instância de objeto possui tacitamente um lock, até mesmo um objeto trivial new Object(). É comum destacar um objeto desses como um lock bem definido:

Object lock = new Object();

Os métodos qualificados como synchronized referenciam o lock de sua própria classe (ou seja, this).

Para esperar uma thread morrer, utiliza-se o método join().

Para esperar um trecho de código executar, pode se utilizado o mecanismo wait() notify().

Tanto o lado que espera quanto o lado que executa devem ser cercados pelo mesmo lock usando-se um bloco synchronized(lock){} em cada thread.

[quote=“hipersoft”]Olá!

Como vc deve saber, toda operação de sincronismo é feita com referência a um lock.

Toda instância de objeto possui tacitamente um lock, até mesmo um objeto trivial new Object(). É comum destacar um objeto desses como um lock bem definido:

Object lock = new Object();

Os métodos qualificados como synchronized referenciam o lock de sua própria classe (ou seja, this).

Para esperar uma thread morrer, utiliza-se o método join().

Para esperar um trecho de código executar, pode se utilizado o mecanismo wait() notify().

Tanto o lado que espera quanto o lado que executa devem ser cercados pelo mesmo lock usando-se um bloco synchronized(lock){} em cada thread.[/quote]

A explicação foi boa mas talvez são estes conceitos que não aprendi na pratica,vc poderia me dar um exemplo pratico disso?

public static void main(String[] args){
   Thread t = new Thread();
   t.run();

   //vai fazer o programa esperar essa thread terminar antes de continuar
   t.join();

   //aqui entra o codigo pra exibir esse resultado que você quer...
}
1 curtida

[quote=“jairelton”][code]
public static void main(String[] args){
Thread t = new Thread();
t.run();

//vai fazer o programa esperar essa thread terminar antes de continuar
t.join();

//aqui entra o codigo pra exibir esse resultado que você quer…
}
[/code][/quote]

Cara é quse isso mesmo que eu quero,na verdade é o seguinte ,eu tenho na minha aplicação a instanciação de um objeto de outra classe,é esse objeto que é do tipo:

class object extends JFrame implements Runnable

Bom no metodo run() dele é que está sendo instanciado a thread.

O Problema é que quando eu instancio esse objeto no contrutor da minha aplicação:

obj  objeto=new obj(); obj.show(); 

Tu ta me sugerindo isso: ?

obj  objeto=new obj(); objeto.show();objeto.start();objeto.join() 

Ja tentei aqui ,não dá certo…creio que é porque no Construtor de obj já há uma chamada ao metodo start()

Não sei se pode ajudar vc, mas tenta o seguinte:
Esse “objeto” que vc declarou é da Thread né, então faz assim:

Thread objeto = new obj(); objeto.start();

Acho q assim funciona.
Nesse caso a sua classe “obj”, extende Thread, então vc deve fazer isso.

Vê se dá certo e avisa ae…

Uma correção no que eu disse acima: join não precisa de lock, somente wait-notify

/**
 * Exemplo de uso de wait-notify
 */
class Teste
{
  static JFrame gui;

  public static void main(String args []) throws InterruptedException
  {
    // Cria a GUI na EDT
    //
    Runnable criaGUIrunnable = new Runnable() 
    {
       public void run() 
       {
         criaGUImetodo();
       }
    };  
    EventQueue.invokeLater(criaGUIrunnable);
    //
    // Lança a thread
    //
    gui.start();
    //
    // Espera a thread executar
    //
    synchronized(Teste.class)
    {
      gui.wait();
    }
    //
    // Mostra o resultado
    //
    ...
  }

  static void  criaGUImetodo()
  {
     gui = new XXXFrame();
     ...
     gui.setVisible(true);
  }
}

class XXXFrame extends JFrame implements Runnable
{
   public void run()
  {
    synchronized(Teste.class)
    {
       // faz o que tem que fazer
       //
       ...
       // notifica a thread que espera
       //
       Teste.class.notifyAll();
    }
  }
}
/**
 * Exemplo usando join
 */
class Teste
{
  static JFrame gui;

  public static void main(String [] args) throws InterruptedException
  {
    // Cria a GUI na EDT
    //
    Runnable criaGUIrunnable = new Runnable() 
    {
       public void run() 
       {
         criaGUImetodo();
       }
    };  
    EventQueue.invokeLater(criaGUIrunnable);
    //
    // Lança a thread
    //
    gui.start();
    //
    // Espera a thread executar
    //
    gui.join();
    //
    // Mostra o resultado
    //
    ...
  }

  static void  criaGUImetodo()
  {
     gui = new XXXFrame();
     ...
     gui.setVisible(true);
  }
}

class XXXFrame extends JFrame implements Runnable
{
   public void run()
  {
     // faz o que tem que fazer
     //
     ...
  }
}

[quote=“Hericksnake”]Não sei se pode ajudar vc, mas tenta o seguinte:
Esse “objeto” que vc declarou é da Thread né, então faz assim:

Thread objeto = new obj(); objeto.start();

Acho q assim funciona.
Nesse caso a sua classe “obj”, extende Thread, então vc deve fazer isso.

Vê se dá certo e avisa ae…[/quote]

O objeto não é da Thread,é de uma classe4 minha que implementa a interface Runnable,ou seja ,ele tem um metodo run()…e dentro desse objeto há instanciação da Thread…

Mas mesmo assim não funcionou? Eu fiz uma coisa parecida e deu certo dessa maneira…

Tiveram coisas no teu codigo…pra ser sincero :razz: até os comentarios do teu codigo são meio esquisitos,o que é isso “EDT”? E quando joguei as principais ideias aqui no meu aplicativo deu em parte certa.

Tipo,ele realmente esperou a thread parar…mas como eu disse o meu objto que implementa Runnable,ele dentro dele tem a instacia de umoutro objeto mapa que é do tipo JFrame.E’mais ou menos a seguinte ideia:Minha aplicação tem um objeto obj,esse obj tem um obj Mapa.Obj é uma classe que implementa Ruinnable…

O que ocorre,é que espera a thread de obj parar sim mas so atualiza o objeto mapa que esta dentro de obj DEPOIS que thread para,mesmo eu colocando os comandos pra atualizar entro do metodo run() ,não se atuializa…

Ou seja,em sinteseeu quero que obj fique rodando,e atualizando a imagem do seu obejto mapa,e ao final termine e execute o proximo comando da minha aplicação principal

Se vc tiver um exemplo de thread sendo parada,por favor,poste ele aqui…pois esse exemplo realmente foi meio confuso até nos comentarios…

e obrigado pela ajuda

Cara deixa ver se eu explico,eu estou complicando muito…

Bom eu tenho a seguinte classe :

public class Classe1 extends Jframe implements Runnable
           {
              Thread ex;
              public Classe1()
               {
                   MApa mapa=new Mapa(valores);
                   if(ex!=null) ex=null;
                   Thread ex=new Thread();
                   ex.start();
                 }

            public void run()
            {
                mapa.update();
                //comando()
             map.update()

            }

}

public class Mapa() extends JPanel{

public paintComponent(Graphics g)
{

//comandos

}

public void update(){
repaint();


}


}

Bom o fato é que eu fiz o seguinte,conforme vc me disse


Classe1 classe=new Classe1()
classe1.ex.start();

try{
          classe1.ex.join();
}
catch(InterruptedException ie){}

execute1();

E ai fica atualizando o mapa ,mostrando os valores em tempo de execução,mas no final não há execução de execute1() o programa fica suspenso

No entanto se eu fizer:


Classe1 classe=new Classe1()


try{
          classe1.ex.join();
}
catch(InterruptedException ie){}

execute1();

Ai ele executa execute1() apos a Thread ser finalisada ,mas o mapa só é atualizado depois que a Thread encerra…

Ou seja ,eu quero é que execute a Thread,fique atualizando mapa e depois ,com ela encerrada,ai sim execute execute1()[/code][/code]

Houve uma confusão.
O código não foi postado por mim e sim pelo “hipersoft”.
Até…

No ex você esta criando um novo objeto de Thread, isso vai criar uma Thread que não vai fazer absolutamente nada, tenta isso:

public class Classe1 extends Jframe implements Runnable
           {
              Thread ex;
              public Classe1()
               {
                   MApa mapa=new Mapa(valores);
                   start();
                 }

            public void run()
            {
                ex = Thread.currentThread();
                mapa.update();
                //comando()
             map.update()

            }

}

OBS: Você não precisa por “Thread ex = …”, pois assim vai estar criando uma variavel local e não vai estar usando a global, use apenas “ex = …”.

OBS2: Você não deve chamar classe1.ex.start(); pois a Thread ex já esta sendo iniciada no construtor.

Espero ter ajudado.

[quote=“Felipe”]No ex você esta criando um novo objeto de Thread, isso vai criar uma Thread que não vai fazer absolutamente nada, tenta isso:

public class Classe1 extends Jframe implements Runnable
           {
              Thread ex;
              public Classe1()
               {
                   MApa mapa=new Mapa(valores);
                   start();
                 }

            public void run()
            {
                ex = Thread.currentThread();
                mapa.update();
                //comando()
             map.update()

            }

}

OBS: Você não precisa por “Thread ex = …”, pois assim vai estar criando uma variavel local e não vai estar usando a global, use apenas “ex = …”.

OBS2: Você não deve chamar classe1.ex.start(); pois a Thread ex já esta sendo iniciada no construtor.

Espero ter ajudado.[/quote]

Obrigado pela resposta,ainda não testei ainda mas queria te perguntar uma coisa que achei estranha …como é que tu dá um start() numa Thread que nem foi iniciada,somente declarada?

Outra coisa,como é o suo do join() pelo programa principal? é tipo:

objetoDaClasse1.ex.join()

???

[quote=“Felipe”]No ex você esta criando um novo objeto de Thread, isso vai criar uma Thread que não vai fazer absolutamente nada, tenta isso:

public class Classe1 extends Jframe implements Runnable
           {
              Thread ex;
              public Classe1()
               {
                   MApa mapa=new Mapa(valores);
                   start();
                 }

            public void run()
            {
                ex = Thread.currentThread();
                mapa.update();
                //comando()
             map.update()

            }

}

OBS: Você não precisa por “Thread ex = …”, pois assim vai estar criando uma variavel local e não vai estar usando a global, use apenas “ex = …”.

OBS2: Você não deve chamar classe1.ex.start(); pois a Thread ex já esta sendo iniciada no construtor.

Espero ter ajudado.[/quote]

Alias fuyio testar agora e escrevi errado aqui no post,no meu codigo eu realmente não estou criando um novo objto não ,estou só dando um new Thread(this) nele ,mas não o redeclaro.

E mais ,teu comando start(); sem referencia de um objeto Thread nem compila…

[quote=“HumbertoJr”][quote=“Felipe”]No ex você esta criando um novo objeto de Thread, isso vai criar uma Thread que não vai fazer absolutamente nada, tenta isso:

public class Classe1 extends Jframe implements Runnable
           {
              Thread ex;
              public Classe1()
               {
                   MApa mapa=new Mapa(valores);
                   start();
                 }

            public void run()
            {
                ex = Thread.currentThread();
                mapa.update();
                //comando()
             map.update()

            }

}

OBS: Você não precisa por “Thread ex = …”, pois assim vai estar criando uma variavel local e não vai estar usando a global, use apenas “ex = …”.

OBS2: Você não deve chamar classe1.ex.start(); pois a Thread ex já esta sendo iniciada no construtor.

Espero ter ajudado.[/quote]

Alias fuyio testar agora e escrevi errado aqui no post,no meu codigo eu realmente não estou criando um novo objto não ,estou só dando um new Thread(this) nele ,mas não o redeclaro.

E mais ,teu comando start(); sem referencia de um objeto Thread nem compila…[/quote]

É verdade, eu tinha escrito rapido e nem tinha me ligado nisso, mas o que estava acontecendo era que você estava criando uma variavel local com o mesmo nome da global, e dai a global permanesse inalterada impossibilitando que seja chamado o metodo join() da Thread

E no meu ex, ao invez de “start();”, seria “new Thread(this).start()”, ai sim, a Thread já seria iniciada no construtor (sem precisar ser iniciada na outra classe).

Se prefirir, ao invez de chamar “ex = Thread.currentThread()” no metodo run, armazene a Thread na variavel ex como você já estava fazendo (só que dessa vez na variavel global :wink:).

Testa ai e posta o resultado.

[quote=“Felipe”][quote=“HumbertoJr”][quote=“Felipe”]No ex você esta criando um novo objeto de Thread, isso vai criar uma Thread que não vai fazer absolutamente nada, tenta isso:

public class Classe1 extends Jframe implements Runnable
           {
              Thread ex;
              public Classe1()
               {
                   MApa mapa=new Mapa(valores);
                   start();
                 }

            public void run()
            {
                ex = Thread.currentThread();
                mapa.update();
                //comando()
             map.update()

            }

}

OBS: Você não precisa por “Thread ex = …”, pois assim vai estar criando uma variavel local e não vai estar usando a global, use apenas “ex = …”.

OBS2: Você não deve chamar classe1.ex.start(); pois a Thread ex já esta sendo iniciada no construtor.

Espero ter ajudado.[/quote]

Alias fuyio testar agora e escrevi errado aqui no post,no meu codigo eu realmente não estou criando um novo objto não ,estou só dando um new Thread(this) nele ,mas não o redeclaro.

E mais ,teu comando start(); sem referencia de um objeto Thread nem compila…[/quote]

É verdade, eu tinha escrito rapido e nem tinha me ligado nisso, mas o que estava acontecendo era que você estava criando uma variavel local com o mesmo nome da global, e dai a global permanesse inalterada impossibilitando que seja chamado o metodo join() da Thread

E no meu ex, ao invez de “start();”, seria “new Thread(this).start()”, ai sim, a Thread já seria iniciada no construtor (sem precisar ser iniciada na outra classe).

Se prefirir, ao invez de chamar “ex = Thread.currentThread()” no metodo run, armazene a Thread na variavel ex como você já estava fazendo (só que dessa vez na variavel global :wink:).

Testa ai e posta o resultado.[/quote]

O que acontece é que o Mapa aparece com escala cinza todo ,a thread fica executando,e ele só desenha o mapa quando a thread termina…eu queria que ficasse desenhando enquanto a thread executa…

Diz ai como fica o join() no programa principal:

objdaClasse1.ex.join()?

Só faltou um pequeno detalhe que eu ainda não tinha visto, no metodo run() você só ta chamando updade() (eu prefiro chamar repaint() direto, pois é uma chamada a metodo a menos, mas isso é você quem decide) uma vez, acho que você deveria por dentro de um while pra executar enquanto não tiver terminado.

E o que seria aquele “// comando()” dentro do run()? No seu codigo, tem alguma coisa ali? Não seria melhor por esse comando() na Thread principal (porque do jeito que ta a Thread principal ta apenas esperando a outra Thread esperar, dai não faz sentido criar duas Thread.

O join() ficaria do jeito que você boto, mas agora que acho que entendi o que você quer, acho que ficaria melhor de outra maneira:

public class Classe1 extends Jframe implements Runnable
           {
              Thread ex;
              boolean compreto;
              public Classe1()
               {
                   completo = false;
                   Mapa mapa=new Mapa(valores);
                   if(ex!=null) ex=null;
                   Thread ex=new Thread(this);
                   ex.start();
                 }

            public void run()
            {
               while (!completo){
                 mapa.update();
                 try{
                  Thread.sleep(50); // pode ser qualquer tempo,
                  // apenas pra não atualizar mais que o necessario
                 }
                 catch (Exception erro){}
               }
            }

}

public class Mapa extends JPanel{

public paintComponent(Graphics g)
{

//comandos

}

public void update(){
repaint();


}


} 
Classe1 classe=new Classe1()
// aqui fica o "comando()"
classe.completo = true;
execute1(); 

Testa isso, deve funcionar.

[quote=“Felipe”]Só faltou um pequeno detalhe que eu ainda não tinha visto, no metodo run() você só ta chamando updade() (eu prefiro chamar repaint() direto, pois é uma chamada a metodo a menos, mas isso é você quem decide) uma vez, acho que você deveria por dentro de um while pra executar enquanto não tiver terminado.

E o que seria aquele “// comando()” dentro do run()? No seu codigo, tem alguma coisa ali? Não seria melhor por esse comando() na Thread principal (porque do jeito que ta a Thread principal ta apenas esperando a outra Thread esperar, dai não faz sentido criar duas Thread.

O join() ficaria do jeito que você boto, mas agora que acho que entendi o que você quer, acho que ficaria melhor de outra maneira:

public class Classe1 extends Jframe implements Runnable
           {
              Thread ex;
              boolean compreto;
              public Classe1()
               {
                   completo = false;
                   Mapa mapa=new Mapa(valores);
                   if(ex!=null) ex=null;
                   Thread ex=new Thread(this);
                   ex.start();
                 }

            public void run()
            {
               while (!completo){
                 mapa.update();
                 try{
                  Thread.sleep(50); // pode ser qualquer tempo,
                  // apenas pra não atualizar mais que o necessario
                 }
                 catch (Exception erro){}
               }
            }

}

public class Mapa extends JPanel{

public paintComponent(Graphics g)
{

//comandos

}

public void update(){
repaint();


}


} 
Classe1 classe=new Classe1()
// aqui fica o "comando()"
classe.completo = true;
execute1(); 

Testa isso, deve funcionar.[/quote]

Cara,

Esse comando é um processamento de calculo de variaveis,mas utiliza metodos randomicos por isso nunca vou saber quanto tempo será suficiente pra que ele termine o processamento…essa solução não dá…

Outra coisa…essa classe que extende Jframe e implementa Runnable…será chamada pela classe principal,cade o join que eu tanto falo?

A tua ultima solução eu ja tinha tentado desse jeito…o problema creio é que ProgramaPrincipal instancia um objeto Classe1 que por sua vez instancia um objeto Mapa…acho que o paintComponent(Graphics g) ,esse objeto “g” a Thread acha que é o programa principal,mas é do Jframe da classe1

Você não ta querendo que o Mapa seja atualizado enquanto são feitos os calculos? Então, se você for esperar a Thread parar com o join(), você vai ter apenas uma Thread rodando, dai vale mais apena usar uma unica Thread.

E o Thread.sleep() é apenas para evitar que fica atualizando demais, afinal, pra que mais de 20 quadros por segundo? Vai apenas gastar tempo de processamento, note que ta dentro do loop do while, o que vai fazer com que continue atualizando enquanto não tiver terminado.

Outra coisa que eu só vi agora, é que você esqueceu de adicionar o Mapa no JFrame, dai não funciona mesmo, tenta isso:

public class Classe1 extends JFrame implements Runnable
           {
              Thread ex;
              boolean compreto;
              public Classe1()
               {
                   completo = false;
                   Mapa mapa=new Mapa(valores);
                   getContentPane().add(mapa);
                   if(ex!=null) ex=null;
                   Thread ex=new Thread(this);
                   ex.start();
                   setVisible(true);
                 }

            public void run()
            {
               while (!completo){
                 mapa.update();
                 try{
                  Thread.sleep(50); // pode ser qualquer tempo,
                  // apenas pra não atualizar mais que o necessario
                 }
                 catch (Exception erro){}
               }
            }

}

public class Mapa extends JPanel{

public paintComponent(Graphics g)
{

//comandos

}

public void update(){
repaint();


}


}
Classe1 classe=new Classe1()
// aqui fica o "comando()"
classe.completo = true;
execute1();