Dúvida sobre Thread

7 respostas
R

Bem, é algo que uso em Java me, mas como a dúvida é sobre Thread resolvi postar aqui.

Pra quem não sabe, em Java me quando se acessa partes do dispositivo, como Camera, sistema arquivos e outros é necessário a utilização de Thread.

Eu posso, fazer algo do tipo:

Thread t = new Thread() {
			public void run() {
				if (!isSaving()) {
					image = recuperarArquivoImpl(sNomeArquivo);
					ImageItem imageItem = new ImageItem(
										"Imagem Carregada", image,
										ImageItem.LAYOUT_CENTER, "Ih deu erro");
								oForm.append(imageItem);					
				}
			}
		};
		t.start();

Só que eu quero pegar o retorno do método em outro lugar, só que o que eu to fazendo abaixo não funciona e ele me traz o retorno nulo, porque não espera a Thread terminar de executar.

public synchronized Image recuperarArquivo(final String sNomeArquivo) {
		Thread t = new Thread() {
			public void run() {
				if (!isSaving()) {
					image = recuperarArquivoImpl(sNomeArquivo);
				}
			}
		};
		t.start();

		return image;
	}

Como que eu faço?

7 Respostas

Tchello

Usei um conceito semelhante quando fiz um pacote de conexão TCP com sockets, pra que não fosse necessário reescrever toda vez que fosse precisar usar sockets novamente.
Geralmente uso uma classe de controle que fica administrando os pacotes e a comunicação entre eles.
Uma característica desse pacote de conexões é que uma thread ficava rodando ali só escutando a rede caso chegassem mensagens e quando isso acontecia ela avisava o método da classe de controle responsável pra tratar esse tipo de evento.
Usei um Singleton no controle e montei uma interface de escutadora que é setado toda vez que alguém começa a usar esse pacote de conexões (assinado pela classe de controle). Assim toda vez que o pacote de conexões recebesse alguma mensagem ele avisa o escutador que foi configurado inicialmente e nem precisa saber que existe classe de Controle, Singleton, etc e tal.

Bom, qualquer coisa posta ai, não sei se fui muito claro mas espero tê-lo ajudado em algo.

Abraços.

renzonuccitelli
public synchronized Image recuperarArquivo(final String sNomeArquivo) {
		Thread t = new Thread() {
			public void run() {
				if (!isSaving()) {
					image = recuperarArquivoImpl(sNomeArquivo);
				}
			}
		};
		t.start();
                t.join()//vai fazer o método esperar o término da Thread.

		return image;
	}

Essa seria uma solução, mas acho meio feio sincronizar desse jeito. Uma outra maneira seria dentro da Thread vc setar a imagem onde vc kiser:

public synchronized voidrecuperarArquivo(final String sNomeArquivo, final ClasseNecessitandoImagem c) {
		Thread t = new Thread() {
			public void run() {
				if (!isSaving()) {
					image = recuperarArquivoImpl(sNomeArquivo);

				}
                                c.setImage(image);
			}
		};
		t.start();
	}
C

o negócio é sincronizar blocos de código…

public synchronized Image recuperarArquivo(final String sNomeArquivo) {   
    Thread t = new Thread() {   
        public void run() {   
            
            synchronized(this){
                
                if (!isSaving()) {   
                     image = recuperarArquivoImpl(sNomeArquivo);   
                 } 
                 
                 //libera os bloqueios após image receber um valor
                 notify();

             }
        }   
    };   
    
    t.start();   
    
    synchronized(t){
       
        try{    
              //aguarda o notify da thread t
              t.wait();
      
         }catch(Exception e){//tratar exception}  

return image;

}

acho que vai dar certo… boa sorte!

renzonuccitelli

carlospia:
o negócio é sincronizar blocos de código…

public synchronized Image recuperarArquivo(final String sNomeArquivo) {   
    Thread t = new Thread() {   
        public void run() {   
            
            synchronized(this){
                
                if (!isSaving()) {   
                     image = recuperarArquivoImpl(sNomeArquivo);   
                 } 
                 
                 //libera os bloqueios após image receber um valor
                 notify();

             }
        }   
    };   
    
    t.start();   
    
    synchronized(t){
       
        try{    
              //aguarda o notify da thread t
              t.wait();
      
         }catch(Exception e){//tratar exception}  

return image;

}

acho que vai dar certo… boa sorte!

Isso aí não vai funcionar não. Além de ter dado um nome de palavra reservada para um método, o que o wait faz é colocar Thread pra dormir, no caso, a Tread t passada como parâmetro. Além disso, o notify acorda uma Thread qualquer que esteja dorminfo, assim vc não garante que será a que vc deseja que seja acordada.

C

renzonuccitelli:
carlospia:
o negócio é sincronizar blocos de código…

public synchronized Image recuperarArquivo(final String sNomeArquivo) {   
    Thread t = new Thread() {   
        public void run() {   
            
            synchronized(this){
                
                if (!isSaving()) {   
                     image = recuperarArquivoImpl(sNomeArquivo);   
                 } 
                 
                 //libera os bloqueios após image receber um valor
                 notify();

             }
        }   
    };   
    
    t.start();   
    
    synchronized(t){
       
        try{    
              //aguarda o notify da thread t
              t.wait();
      
         }catch(Exception e){//tratar exception}  

return image;

}

acho que vai dar certo… boa sorte!

Isso aí não vai funcionar não. Além de ter dado um nome de palavra reservada para um método, o que o wait faz é colocar Thread pra dormir, no caso, a Tread t passada como parâmetro. Além disso, o notify acorda uma Thread qualquer que esteja dorminfo, assim vc não garante que será a que vc deseja que seja acordada.



“Além de ter dado um nome de palavra reservada para um método”
- onde? seria “syncrhonized” dentro do método? se sim, isso não é um método, é um recurso do java ( sincronizar blocos de código ).

“o que o wait faz é colocar Thread pra dormir”
- quem faz isso é o sleep!

" notify acorda uma Thread" - o notify() retira do bloqueio o bloco wait(). Estes devem sempre trabalhar
juntos e sempre em um contexto sincronizado. synchronized(this){}, synchronized(t){} !!!

bom, na dúvida testei o exemplo que fiz, e funcionou perfeitamente.

vou deixar um link para reforçar os seus conceitos!

http://www.javawiki.com.br/example.action?id=126601

pois vejo que tens interesse no assunto,

faça uns testes!

[]´s

renzonuccitelli

Opa Carlos, obrigado pelo link.

Realmente não conhecia esse uso do syncronized, mas uma coisa pra eu aprender :D

Contudo, não estou enganado quando ao método notify. Se vc perceber no próprio código do link que me passou, o desbloqueio é feito quando a variável aguarde é setada como false, e o bloqueio acontece quando a mesma é setada true. Isso é feito no código porque a Thread não sabe qual outra Thread chamou o notify(). O seu exemplo funcionou porque só tinha uma Thread esperando, faça teste com três e veras que o notify pode fazer rodar qualquer uma das duas. Fica aqui tb um link pra vc dar uma olhada no método notify.

public class LancadoraDeNotify extends Thread {
	public void run(){
		new ThreadEspera("Thread 1 rodando...",this).start();
		new ThreadEspera("Thread 2 rodando...",this).start();
		new ThreadEspera("Thread 3 rodando...",this).start();
		while(true){
			try {
				sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			synchronized(this){
			notify();
			}
			System.out.println("executou notify");
		}
	}
	
	public static void main(String[] args){
		
		new LancadoraDeNotify().start();
		
	
	}

}
public class ThreadEspera extends Thread {
	LancadoraDeNotify lancadora;
	public ThreadEspera(String mensagem,LancadoraDeNotify lancadora) {
		super();
		this.mensagem = mensagem;
		this.lancadora=lancadora;
	}

	private String mensagem;
	
	public void run(){
		
		while(true){
			System.out.println(mensagem);
			try {synchronized(lancadora){
				System.out.println("Thread esperando...");
				lancadora.wait();
				
			}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
		
		}
	}

}
C

Então Renzo,

Threads nunca foi um assunto simples! Gostaria de fazer uma observação:

“Isso é feito no código porque a Thread não sabe qual outra Thread chamou o notify()”

digo o seguinte, uma thread sempre saberá qual wait deverá liberar através da referencia “this”.

Como cada um dos this passados em new ThreadEspera é uma instância diferente de LancadoraDeNotify, ocorrerá um “link” entre as referencias:

//primeira instancia this
new ThreadEspera("Thread 1 rodando...",this).start(); 

//segunda instancia this 
new ThreadEspera("Thread 2 rodando...",this).start(); 

//terceira instancia this 
new ThreadEspera("Thread 3 rodando...",this).start()
//recebe a referencia "this" passada em new ThreadEspera("Thread 1 rodando...",this).start();
this.lancadora=lancadora;

neste momento é feito um “link” entre wait() e notify(), veja:

try { //lancadora é a referencia "this" passada em new ThreadEspera("Thread 1 rodando...",this).start(); synchronized(lancadora){ System.out.println("Thread esperando..."); lancadora.wait(); } }

assim eu te digo que wait e notify são bem organizados e garantidos!

Com relação ao link que passou… já estava nos meus favoritos! :slight_smile:

valeu

Criado 27 de janeiro de 2009
Ultima resposta 28 de jan. de 2009
Respostas 7
Participantes 4