Problema no método wait da Thread

7 respostas
aix

Ola pessoal, estive estudando pelo livro da kathy para a certificação e em um exercício de Thread não consigo entender o porque utilizando o método wait no meu linux fica travado e não vai, ai resolvi testar num micro que tenho windows com a mesma jre e funciona blz, mas no meu notebook não funciona assim é como se o notify(); não tivesse executando, sera alguma configuração que esta errada ?

uso linux fedora core10
e meu micro e um core2 duo
com java6

se alguem que ja passou por isso ficaria grato se me disserem o porque, abraços e vlw. aqui vai o cod

pessoal se eu colocar tempo dentro do wait ai funciona blz. se eu não fizer isso fica la parado “esperando b”

package charpter09;

public class ThreadA  {

	public static void main(String[] args) {
		// Criar um objeto Thread B
		ThreadB b = new ThreadB();
		// Chamar o metodo run()
		b.start();
		//sincronização
		synchronized (b) {
			System.out.println("Esperando por b");
			// chamar o metodo wait();
			
			try {
				
				b.wait();
				
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(b.valor);
			
		}
		
		
	}
}
package charpter09;

public class ThreadB extends Thread{

	int valor;
	
	public void run(){
		synchronized (this) {
			for(int i = 0; i < 100; i ++){
				valor += i;
			}
			notify();
		}
	}
	
	
}

7 Respostas

victorwss

Pelo visto você não entendeu como wait e notify funcionam.
wait sem notify é pedir para que o seu programa trave.
notify sem wait simplesmente não faz nada.
wait e notify (ou notifyAll) só fazem sentido quando aparecem juntos.

Vamos supor que a Thread A chama o método wait do objeto X e depois disso a Thread B chama o método notify do mesmo objeto X. Eis o que acontece.

  1. A Thread A está executando tranquila e alegre quando encontra um synchronized (x).
  2. Então, a Thread A adquire a trava do objeto x, ou se esta estiver ocupada, espera até desocuparem ela para obtê-la.
  3. Tendo a trava do objeto x, a Thread A prossegue alegremente até encontrar um x.wait().
  4. Então Thread A diz: “vou dormir até alguém me notificar para continuar por meio do objeto x”.
  5. Então a Thread A larga a trava do objeto x e vai dormir.
  6. Algum tempo depois, a Thread B também encontrou um synchronized (x), provavelmente em algum lugar bem distante de onde a Thread A está.
  7. A Thread B obtém então a trava do objeto x, que foi largada pela Thread A.
  8. A Thread B continua feliz e executando o seu código, quando encontra um x.notify().
  9. Então a Thread B diz: “alguém que está dormindo esperando o objeto x ser notificado, já pode acordar!”.
  10. A Thread A acorda, em resposta ao notify, e tenta adquirir a trava do objeto x. Mas como a Thread B ainda está usando, a Thread A fica esperando a trava liberar.
  11. A Thread B executa mais alguns passos e sai do seu bloco synchronized (x), liberando a trava do objeto x, e então ela continua o seu trabalho seguindo com a sua vida.
  12. A Thread A vê que a trava do x está agora livre, então ela pega a trava e continua o seu trabalho logo após o lugar onde ela tinha parado no x.wait().
  13. Pouco depos a Thread A sai do bloco synchronized (x), solta a trava do objeto x e continua seguindo com a sua vida.

Quanto ao notifyAll, a diferença é que no notify a Thread diz: “alguém que está dormindo esperando o objeto x ser notificado, já pode acordar!”. Se estiver 50 Threads dormindo esperando o objeto x, só uma delas acorda. Com o notifyAll, a Thread diz: “todo mundo que está dormindo esperando o objeto x ser notificado, já pode acordar!”, e então todas as Threads que estiverem dormindo esperando o notify, vão acordar. Apesar de todas as Threads acordarem, somente uma de cada vez vai adquirir a trava do objeto x.

Edit: hmm, vendo o seu exemplo, acho que você entendeu sim, desculpe. O que ocorre é que é possível que o notify venha antes do wait. E se isso acontecer o resultado pode ser uma tragédia.

aix

victorwss:
Pelo visto você não entendeu como wait e notify funcionam.
wait sem notify é pedir para que o seu programa trave.
notify sem wait simplesmente não faz nada.
wait e notify (ou notifyAll) só fazem sentido quando aparecem juntos.

Vamos supor que a Thread A chama o método wait do objeto X e depois disso a Thread B chama o método notify do mesmo objeto X. Eis o que acontece.

  1. A Thread A está executando tranquila e alegre quando encontra um synchronized (x).
  2. Então, a Thread A adquire a trava do objeto x, ou se esta estiver ocupada, espera até desocuparem ela para obtê-la.
  3. Tendo a trava do objeto x, a Thread A prossegue alegremente até encontrar um x.wait().
  4. Então Thread A diz: “vou dormir até alguém me notificar para continuar por meio do objeto x”.
  5. Então a Thread A larga a trava do objeto x e vai dormir.
  6. Algum tempo depois, a Thread B também encontrou um synchronized (x), provavelmente em algum lugar bem distante de onde a Thread A está.
  7. A Thread B obtém então a trava do objeto x, que foi largada pela Thread A.
  8. A Thread B continua feliz e executando o seu código, quando encontra um x.notify().
  9. Então a Thread B diz: “alguém que está dormindo esperando o objeto x ser notificado, já pode acordar!”.
  10. A Thread A acorda, em resposta ao notify, e tenta adquirir a trava do objeto x. Mas como a Thread B ainda está usando, a Thread A fica esperando a trava liberar.
  11. A Thread B executa mais alguns passos e sai do seu bloco synchronized (x), liberando a trava do objeto x, e então ela continua o seu trabalho seguindo com a sua vida.
  12. A Thread A vê que a trava do x está agora livre, então ela pega a trava e continua o seu trabalho logo após o lugar onde ela tinha parado no x.wait().
  13. Pouco depos a Thread A sai do bloco synchronized (x), solta a trava do objeto x e continua seguindo com a sua vida.

Quanto ao notifyAll, a diferença é que no notify a Thread diz: “alguém que está dormindo esperando o objeto x ser notificado, já pode acordar!”. Se estiver 50 Threads dormindo esperando o objeto x, só uma delas acorda. Com o notifyAll, a Thread diz: “todo mundo que está dormindo esperando o objeto x ser notificado, já pode acordar!”, e então todas as Threads que estiverem dormindo esperando o notify, vão acordar. Apesar de todas as Threads acordarem, somente uma de cada vez vai adquirir a trava do objeto x.

Edit: hmm, vendo o seu exemplo, acho que você entendeu sim, desculpe. O que ocorre é que é possível que o notify venha antes do wait. E se isso acontecer o resultado pode ser uma tragédia.

caro Victor, com relação ao uso dos métodos wait e notify as duvidas foram bastante esclarecidas. No entanto, a minha principal duvida é: por que o mesmo código funciona perfeitamente no sistema operacional windows, enquanto que no linux o mesmo código não é executado. Sei que é uma duvida muito genérica, no entanto as versões do java são iguais e a versão da IDE tambem.

T

De fato, a thread foi executada tão rapidamente no Linux que o notify foi executado antes do wait. Isso ocorreu porque o método que está na thread não tem absolutamente nada que chame o sistema operacional exceto o próprio notify, e o método que dá o wait imprimiu na tela alguma coisa.

victorwss

Porque o código depende de uma condição de corrida para funcionar. A Thread A tem que alcançar o wait antes que a Thread B chegue no notify, senão o código trava. A velocidade e ordem de execução das Threads costuma ficar a cargo do sistema operacional. Não sei os detalhes da implementação de escalonamento de Threads no sistema operacional, mas o windows está escalonando de uma forma que a Thread A é mais rápida, enquanto que o linux está escalonando de forma que a Thread B é mais rápida.

aix

thingol:
De fato, a thread foi executada tão rapidamente no Linux que o notify foi executado antes do wait. Isso ocorreu porque o método que está na thread não tem absolutamente nada que chame o sistema operacional exceto o próprio notify, e o método que dá o wait imprimiu na tela alguma coisa.

como eu faço para saber se o notify foi executado antes da chamada do método wait. E como eu procedo, se é que existe como, garantir ou tentar garantir a chamada do método wait antes da chamada do metodo notify ?

victorwss

aix:
thingol:
De fato, a thread foi executada tão rapidamente no Linux que o notify foi executado antes do wait. Isso ocorreu porque o método que está na thread não tem absolutamente nada que chame o sistema operacional exceto o próprio notify, e o método que dá o wait imprimiu na tela alguma coisa.

como eu faço para saber se o notify foi executado antes da chamada do método wait. E como eu procedo, se é que existe como, garantir ou tentar garantir a chamada do método wait antes da chamada do metodo notify ?

Você pode criar alguma outra classe que utilize wait e notify internamente para garantir isso e então usar esta classe sempre, ou então você pode utilizar uma das classes do pacote java.util.concurrent, como CountdownLatch, por exemplo. No entanto, a prova de certificação não cobra isso.

aix

victorwss:
aix:
thingol:
De fato, a thread foi executada tão rapidamente no Linux que o notify foi executado antes do wait. Isso ocorreu porque o método que está na thread não tem absolutamente nada que chame o sistema operacional exceto o próprio notify, e o método que dá o wait imprimiu na tela alguma coisa.

como eu faço para saber se o notify foi executado antes da chamada do método wait. E como eu procedo, se é que existe como, garantir ou tentar garantir a chamada do método wait antes da chamada do metodo notify ?

Você pode criar alguma outra classe que utilize wait e notify internamente para garantir isso e então usar esta classe sempre, ou então você pode utilizar uma das classes do pacote java.util.concurrent, como CountdownLatch, por exemplo. No entanto, a prova de certificação não cobra isso.

Obrigado Victor e a Thingol, obrigado pela ajuda, ficou bem claro.

Criado 17 de janeiro de 2009
Ultima resposta 17 de jan. de 2009
Respostas 7
Participantes 3