Aguardar o retorno de um método com Thread

Olá a todos.

É o seguinte pessoal, estou com uma dúvida em relação a sincronização das Thread. Preciso que um método do “objeto A” aguarde o retorno de um método no “Objeto B”, mas dentro método do “Objeto B” eu preciso esperar que uma variável booleana fique false para ela poder retornar. Tipo:


//metodo do objetoA
public boolean action(){
      return objetoB.verificarDados();
}

//verificarDados(); do objetoB
public synchronized boolean verificarDados(){
     lock = true; //Indica que iniciou a verificação e aguarda.
     while(lock){

     }

     return true;
}

Se eu fizer isto, o while ficará travando toda a execução (até mesmo do método de verificação). Embora que, essa variável lock ficará em um loop e a qualquer momento da execução ela ficará false, e quando ficar, o método verificarDados() irá retornar true.

Então, preciso que no momento que eu chamar o verificaDados(), este espere que a veriável lock fique false para ele poder retornar ao outro método.

Alguém poderia dar uma ajuda? Obrigado desde já.

Bom, utilizei o método join() para esperar o término da Thread.

Só que o problema é que se eu utilizar o join() ela irá pausar a execução das outras Threads…

[quote=rdgo94]Olá a todos.

É o seguinte pessoal, estou com uma dúvida em relação a sincronização das Thread. Preciso que um método do “objeto A” aguarde o retorno de um método no “Objeto B”, mas dentro método do “Objeto B” eu preciso esperar que uma variável booleana fique false para ela poder retornar. Tipo:


//metodo do objetoA
public boolean action(){
      return objetoB.verificarDados();
}

//verificarDados(); do objetoB
public synchronized boolean verificarDados(){
     lock = true; //Indica que iniciou a verificação e aguarda.
     while(lock){

     }

     return true;
}

Se eu fizer isto, o while ficará travando toda a execução (até mesmo do método de verificação). Embora que, essa variável lock ficará em um loop e a qualquer momento da execução ela ficará false, e quando ficar, o método verificarDados() irá retornar true.

Então, preciso que no momento que eu chamar o verificaDados(), este espere que a veriável lock fique false para ele poder retornar ao outro método.

Alguém poderia dar uma ajuda? Obrigado desde já.

[/quote]

[quote=rdgo94]Bom, utilizei o método join() para esperar o término da Thread.

Só que o problema é que se eu utilizar o join() ela irá pausar a execução das outras Threads…

[/quote]
Isso está correto.
synchronized garante que a thread só irá executar este codigo se ela estiver a posse do lock. Ou seja, as outras threads irão esperar a execução.
join:
http://docs.oracle.com/javase/tutorial/essential/concurrency/join.html

vc poderia exemplificar melhor o que quer fazer e buscar entender o ciclo de vida de uma thread. Por que não posta um exemplo bem pequeno do que gostaria de fazer? Precisamos saber se vc está estendendo de thread ou runnable… Ver suas classes, mesmo que simples, ajudaria. coloco loops dentro do metodo run.
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/

Dá uma olhada neste tutorial:
http://www.javabeginner.com/learn-java/java-threads-tutorial

[quote=Luiz Augusto Prado][quote=rdgo94]Olá a todos.

É o seguinte pessoal, estou com uma dúvida em relação a sincronização das Thread. Preciso que um método do “objeto A” aguarde o retorno de um método no “Objeto B”, mas dentro método do “Objeto B” eu preciso esperar que uma variável booleana fique false para ela poder retornar. Tipo:


//metodo do objetoA
public boolean action(){
      return objetoB.verificarDados();
}

//verificarDados(); do objetoB
public synchronized boolean verificarDados(){
     lock = true; //Indica que iniciou a verificação e aguarda.
     while(lock){

     }

     return true;
}

Se eu fizer isto, o while ficará travando toda a execução (até mesmo do método de verificação). Embora que, essa variável lock ficará em um loop e a qualquer momento da execução ela ficará false, e quando ficar, o método verificarDados() irá retornar true.

Então, preciso que no momento que eu chamar o verificaDados(), este espere que a veriável lock fique false para ele poder retornar ao outro método.

Alguém poderia dar uma ajuda? Obrigado desde já.

[/quote]

[quote=rdgo94]Bom, utilizei o método join() para esperar o término da Thread.

Só que o problema é que se eu utilizar o join() ela irá pausar a execução das outras Threads…

[/quote]
Isso está correto.
synchronized garante que a thread só irá executar este codigo se ela estiver a posse do lock. Ou seja, as outras threads irão esperar a execução.
join:
http://docs.oracle.com/javase/tutorial/essential/concurrency/join.html

vc poderia exemplificar melhor o que quer fazer e buscar entender o ciclo de vida de uma thread. Por que não posta um exemplo bem pequeno do que gostaria de fazer? Precisamos saber se vc está estendendo de thread ou runnable… Ver suas classes, mesmo que simples, ajudaria. coloco loops dentro do metodo run.
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/

Dá uma olhada neste tutorial:
http://www.javabeginner.com/learn-java/java-threads-tutorial[/quote]

Olá, primeiramente obrigado pela resposta. Vou tentar explicar melhor a situação, não irei postar o código inteiro pois é muito grande, mas é seguinte:

O Projeto trabalha com frames e a cada frame novo (uma imagem da camera) é desencadeada uma nova Thread. Estou trabalhando com o OpenNI para sensores de profundidade.
Na classe Principal.java tenho métodos que implementam MouseListener, um deles é o mouseClicked que ao disparar um evento de clique ele vai até o objeto responsável por iniciar a calibração:

Principal.java

//...outros códigos
Monitor monitor = new Monitor();

	@Override
			public void mouseClicked(MouseEvent arg0) {
//Aqui estou usando o padrão State
				if(monitor.acao(MenuOptions.CALIBRATE)){
					System.out.println("CALIBRADO");					 
				}
				
			}

//...outros códigos

Lá na classe Monitor.java terá o método acao que instanciará um objeto conforme o Enum. Neste caso, para calibragem:

Monitor.java

public class Monitor{
       //...outros codigos

		@Override
		public boolean acao(MonitorOptions option){
			switch(option.getOption()){
				case 1:
					state = new StartMonitorState();
				break;
				
				case 2:
					state = new PauseMonitorState();
				break;
				
				case 3:
					state = new CalibrateMonitorState();
				break;
				
				default:
					state = new StartMonitorState();
			}
			return state.startAction(this);
		}
}

Calibragem.java

public class Calibragem implements MonitorState{

	@Override
	public synchronized boolean startAction() {
        Thread t = new Thread(new Runnable({
			@Override
			public void run() {
		        ControllerFrame controllerF = ((ControllerFrame)interactionMonitor);	
		        controllerF.startCalibrate();
			}
	});
        t.start();
		
		return true;
	}

}

ControllerFrame.java

public class ControllerFrame{
   private volatile boolean;

//..Outros códigos
public  boolean startCalibrate(){
	    	startCalibrate = true;
                while(startCalibrate){    }
                return true;
}


public synchronized void onNewFrame(){
   
  //Aqui fica toda a parte do processamento de cada frame. Assim, quando ha um novo frame esse método é chamado desencadeando uma nova Thread. Isso é padrão do OpenNI.

      
}

//..Outros códigos
}

Então o que eu realmente preciso é:

Ao clicar ele desencadeie em sequencia: clique -> inicie a calibração e espere à terminar para depois poder retornar true. E depois que a calibração terminar ele apareça “CALIBRADO”.

Mas se eu der um join ou mesmo aquele while ele irá travar a execução, consequentemente os novos frames contendo as imagens ficará travada.

onde vc implementou seu metodo run() ?

não vi a dificuldade ainda

[quote=eduJava]onde vc implementou seu metodo run() ?

não vi a dificuldade ainda[/quote]

Ah sim, o método run() está ali na Thread mesmo, acho que apaguei ali sem querer. Mas está corrigido.

Então, eu precisava que o método não retornasse enquanto estivesse calibrando ou seja, antes de terminar a calibragem. Pois ele retorna true para o método anterior e deixa a Thread rodando até morrer mesmo que a calibragem esteja em execução ainda.

E se eu fazer um while ou um join para esperar o estado da variável booleana startCalibrate mudar para false, as outras Threads responsáveis pela captura dos frames pausarão. Pois uma outra Thread no método onNewFrame() é que ficará responsável pela calibração indicando também se terminou ou não (alterando o estado da variável booleana).

Então primeiro
pq usar thread, vc não pode simplesmente chamar o metodo verificarDados e esperar ele retornar e fazer oq tem q fazer?

pegue esse código abaixo e ajuste pra mim ver como vc quer dai eu tento te ajudar

[code]public class Teste4 {
public static void main(String[] args) {
try {
System.out.println(new Teste4().calibrar());
} catch (Exception e) {
e.printStackTrace();
}
}

private boolean calibrar() throws InterruptedException{
	Calibragem c  = new Calibragem();
	
	Thread t = new Thread(c);
	t.start();
	
	while (!c.calibrado) {
		System.out.println("Não está calibrado ainda");
		Thread.sleep(2000);
	}
	System.out.println("Está calibrado");
	
	return c.calibrado;
}

}

class Calibragem implements Runnable{

boolean calibrado = false;

public void run() {
	verificaDados();
	calibrado = true;
	System.out.println("calibrado thread");
}

public void verificaDados(){
	for (int i = 0; i < 5; i++) {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

}[/code]

[quote=eduJava]Então primeiro
pq usar thread, vc não pode simplesmente chamar o metodo verificarDados e esperar ele retornar e fazer oq tem q fazer?
[/quote]

Então, não dá para esperar ele retornar, porque ele faz uma calibração em uma determinada faixa de quadros (200, 500, 1000 etc) em tempo de execução. E essa calibração ocorre toda vez que um novo frame é criado. E tem um método específico para isso (do próprio framework), assim, eu implemento esse método fazendo a verificação nele.

Portanto, ele necessita duas tarefas ao mesmo tempo. Uma para fazer as verificações dos quadros e a outra para esperar que essa verificação acabe (essa thread só acaba quando a aplicação acaba).

O seu código é quase isso mesmo que preciso fazer, só que se eu der um Thread.Sleep() a mesma irá travar a Thread de captura de imagens.

[code] public class Teste4 {
public static void main(String[] args) {
try {
System.out.println(new Teste4().calibrar());
} catch (Exception e) {
e.printStackTrace();
}
}

    private boolean calibrar() throws InterruptedException{  
        Calibragem c  = new Calibragem();  
          
        Thread t = new Thread(c);  
        t.start();  
          
        while (!c.calibrado) {  
            System.out.println("Não está calibrado ainda");  
        }  
        System.out.println("Está calibrado");  
          
        return c.calibrado;  
    }  
}  
  
class Calibragem implements Runnable{  
      
    boolean calibrado = false;  
    boolean isCalibrating = false;


    public void run() {  
         calibrado = true; 

         //Como ali no método onNewFrame() ficaria rodando a todo tempo, eu teria que esperar a variável ficar false
         //Pois o onNewFrame() é chamado a todo momento a cada novo frame (são 30fps), então pensei ali em fazer um while igual está no calibrar(), mas não adiantou
        
        /* while(calibrado) {   }  */
        System.out.println("calibrado thread");  
    }  
    
    //Aqui é um método que implementa uma interface do framework
    public void onNewFrame(){  
        while(frameData.remaining() > 0) {
            //Ele calcula cada pixel, portanto, um quadro de 640x480 ficaria rodando a cada pixel = 307200 pixels. Isso é do OpenNI mesmo. Deve ter um while assim mesmo.
            int depth = (int)frameData.getShort() & 0xFFFF;    
            short pixel = (short)mHistogram[depth];
            mImagePixels[pos] = 0xFF000000 | (pixel << 16) | (pixel << 8);

            if(calibrado){
                //Começa o processo de calibração
                ++cont;
            }

            //.....

            if(cont == 100){
                calibrado = false;
                isCalibrating  = false;
            }
        }


    }  
}  [/code]

usei o wait e depois o notify() para o controle.

Mas o problema é que ele retorna ao método anterior antes da thread terminar seu processamento.

[quote=rdgo94]
Olá, primeiramente obrigado pela resposta. Vou tentar explicar melhor a situação, não irei postar o código inteiro pois é muito grande, mas é seguinte:

O Projeto trabalha com frames e a cada frame novo (uma imagem da camera) é desencadeada uma nova Thread. Estou trabalhando com o OpenNI para sensores de profundidade.
Na classe Principal.java tenho métodos que implementam MouseListener, um deles é o mouseClicked que ao disparar um evento de clique ele vai até o objeto responsável por iniciar a calibração:

Principal.java

//...outros códigos
Monitor monitor = new Monitor();

	@Override
			public void mouseClicked(MouseEvent arg0) {
//Aqui estou usando o padrão State
				if(monitor.acao(MenuOptions.CALIBRATE)){
					System.out.println("CALIBRADO");					 
				}
				
			}

//...outros códigos

Lá na classe Monitor.java terá o método acao que instanciará um objeto conforme o Enum. Neste caso, para calibragem:

Monitor.java

public class Monitor{
       //...outros codigos

		@Override
		public boolean acao(MonitorOptions option){
			switch(option.getOption()){
				case 1:
					state = new StartMonitorState();
				break;
				
				case 2:
					state = new PauseMonitorState();
				break;
				
				case 3:
					state = new CalibrateMonitorState();
				break;
				
				default:
					state = new StartMonitorState();
			}
			return state.startAction(this);
		}
}

Calibragem.java

public class Calibragem implements MonitorState{

	@Override
	public synchronized boolean startAction() {
        Thread t = new Thread(new Runnable({
			@Override
			public void run() {
		        ControllerFrame controllerF = ((ControllerFrame)interactionMonitor);	
		        controllerF.startCalibrate();
			}
	});
        t.start();
		
		return true;
	}

}

ControllerFrame.java

public class ControllerFrame{
   private volatile boolean;

//..Outros códigos
public  boolean startCalibrate(){
	    	startCalibrate = true;
                while(startCalibrate){    }
                return true;
}


public synchronized void onNewFrame(){
   
  //Aqui fica toda a parte do processamento de cada frame. Assim, quando ha um novo frame esse método é chamado desencadeando uma nova Thread. Isso é padrão do OpenNI.

      
}

//..Outros códigos
}

Então o que eu realmente preciso é:

Ao clicar ele desencadeie em sequencia: clique -> inicie a calibração e espere à terminar para depois poder retornar true. E depois que a calibração terminar ele apareça “CALIBRADO”.

Mas se eu der um join ou mesmo aquele while ele irá travar a execução, consequentemente os novos frames contendo as imagens ficará travada.[/quote]

Novamente eu sugiro vc postar algo simples, de como vc esperava que seu programa funcionasse ou descrevesse, e se necessário desenhasse, seu caso de uso.
Por que não posta apenas algo simples, que apenas simule o que quer realizar. Vc sabe onde está o erro? Eu também não sei porque não estou entendendo o que quer.
Seu projeto parece ser muito interessante, mas isso não depende dos sensores.

Pelo que to vendo o seu if tem um método “monitor.acao(MenuOptions.CALIBRATE)” que é uma thread… isso não vai funcionar. O if, ele pega o resultado da função instantaneamente. Nesse if, se quer fazer o trem funcionar, deve chamar um método sincronized (ai sim nenhuma classe chamará este método até o resultado ter sido dado ao seu if). Ou seja, o método que é chamado pelo if não pode conter threads, mas pode chamar um método que verifica os estados de variáveis que as threads estão trabalhando… O if não vai ficar esperando a thread terminar. Simplesmente vai lancar erro na tela do usuário.

Dá uma olhada neste tutorial:
http://www.javabeginner.com/learn-java/java-threads-tutorial