Thread wait e notifyAll - Duvida

9 respostas
jjose

Duvida,

A threadC não continua, não recebe o notifyAll da ThreadA.

class ThreadA {
		
		public static void main(String[] args) {
			
			ThreadC c = new ThreadC();
			c.start();
			
			ThreadB b = new ThreadB();
			b.start();
			
			synchronized (b) {
				try {
					System.out.println("ThreadA Inicia");
					System.out.println("ThreadA Notifica todos e finaliza");
					b.notifyAll();
				} catch (Error e) {
					e.printStackTrace();
				}
			}
		}
	 }	
		
	class ThreadB extends Thread {
					
		public void run() {
			synchronized (this) {
				try {
					System.out.println("ThreadB aguarda ThreadA");
					this.wait();
					System.out.println("ThreadB Finaliza");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	class ThreadC extends Thread {
		
		public void run() {
			synchronized (this) {
				try {
					System.out.println("ThreadC aguarda ThreadA");
					this.wait();
					System.out.println("ThreadC Finaliza");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

Sabem o motivo?

Vlw

9 Respostas

yastorm

Acho que é porque o contexto da sincronização na main Thread está no objeto b. Logo, o notifyAll irá propagar apenas para a Thread b, pos a Thread c está sincronizando para si mesmo.

rodrigo.bossini

Exatamente. O Notify (ou notifyAll, como neste caso) “notifica” somente a(s) thread(s) que estiverem aguardando no objeto em que você chama o notify (ou notifyAll).

A Thread C ficará aguardando eternamente, já que você nunca chama notify no objeto que representa a thread C, que por acaso é o objeto em que ela espera.

jjose

Entendi, nesse caso , basta eu colocar um notify para C tambem.

O que eu queria é ver o notifyAll propagando a liberação de mais thread, alguem sabe como fazer isso no exemplo?

rodrigo.bossini

Você pode, por exemplo, criar um objeto no metodo main, e passar ele para ambas as threads, B e C, via construtor, e fazê-lar dar wait neste objeto. Assim no main, você dá um notifyAll neste objeto e ambas as threads B e C serão afetadas. Só tome cuidado que seu código é arriscado: Main pode invocar notifyALL antes que uma das threads B ou C, ou até mesmo as duas tenham invocado wait. Neste caso as duas ficaram aguardando para sempre.

jjose

O que eu entendi é o código em baixo e não funciona, trava geral. Seu eu coloco wait no contrutor da ThreadA a thread principal fica esperando eternamento.

Eu não entendi mesmo. Podem me ajudar via codigo para eu entender? Sem while, for… coisa simples mesmo

class ThreadA extends Thread{

public ThreadA(ThreadB b, ThreadC c) throws InterruptedException {
	b.start();
	c.start();
}

public static void main(String[] args) throws InterruptedException {  
	
	ThreadB b = new ThreadB();
	ThreadC c = new ThreadC();
	
	ThreadA threadA = new ThreadA(b, c);
	
	synchronized (threadA) {
		threadA.notifyAll();
	}
	
	System.out.println("Fim");
}

}
yastorm

Acho que você não entendeu o que o amigo quis dizer. As três Threads precisam ter um objeto em comum. As Thread b e c não fazem ideia de que a Thread a existe.

Olhe abaixo:
class Reader extends Thread {
	Calculator c;

	public Reader(Calculator calc) {
		c = calc;

	}

	public void run() {
		synchronized (c) {
			try {
				System.out.println("Waiting for calculation...");
				c.wait();
			} catch (InterruptedException e) {
			}
			System.out.println("Total is: " + c.total);
		}
	}

	public static void main(String[] args) {
		Calculator calculator = new Calculator();
		new Reader(calculator).start();
		new Reader(calculator).start();
		new Reader(calculator).start();
		calculator.start();
	}
}

class Calculator extends Thread {
	int total;

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

Olhe esse exemplo que tirei do livro da Kathy. Os objetos Reader tem um objeto Calculator em comum. Esse é o elo de ligação entre o notify.

jjose

yastorm:
Acho que você não entendeu o que o amigo quis dizer. As três Threads precisam ter um objeto em comum. As Thread b e c não fazem ideia de que a Thread a existe.

Olhe abaixo:

public void run() { synchronized (this) { for (int i = 0; i < 100; i++) { total += i; } //notifyAll(); } } }

Olhe esse exemplo que tirei do livro da Kathy. Os objetos Reader tem um objeto Calculator em comum. Esse é o elo de ligação entre o notify.

Eu tinha visto esse exemplo e o que pegou dele é, com ou sem o notifyAll o resultado é o mesmo.

Estou boiando nesse notifyAll :shock:

jjose

Ninguem? Hehehe

E

Rode o programa abaixo e veja por que talvez você esteja tendo problemas.

De modo geral, wait + notify é a mesma coisa que goto para threads; é uma forma muito básica e muito difícil de usar. Se precisar de sincronização entre threads, use alguma classe de java.util.concurrent.

package guj;

class Thread1 implements Runnable {
	public Thread1 (Object lock) { this.lock = lock; }
	@Override
	public void run() {
		System.out.println ("Thread 1 está esperando...");
		synchronized (lock) {
			try {
				lock.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println ("Thread 1 foi acordada");
	}
	private Object lock;
}
class Thread2 implements Runnable {
	public Thread2 (Object lock) { this.lock = lock; }
	@Override
	public void run() {
		System.out.println ("Thread 2 está esperando...");
		synchronized (lock) {
			try {
				lock.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println ("Thread 2 foi acordada");
	}
	private Object lock;
}
class Thread3 implements Runnable {
	public Thread3 (Object lock) { this.lock = lock; }
	@Override
	public void run() {
		System.out.println ("Thread 3 está esperando...");
		synchronized (lock) {
			try {
				lock.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println ("Thread 3 foi acordada");
	}
	private Object lock;
}

public class TesteNotifyAll {
	public static void main (String[] args) {
		Object lock = new Object();
		Thread thr1 = new Thread (new Thread1(lock));
		Thread thr2 = new Thread (new Thread2(lock));
		Thread thr3 = new Thread (new Thread3(lock));
		thr1.start();
		thr2.start();
		thr3.start();
		// Note que aqui estou dando tempo suficiente para todas as threads iniciarem.
		// Você não pode acordar uma thread (que está em wait) se ela ainda não chegou 
		// no wait! Pode ser isso que deu problema no seu programa. 
		// E é por isso que é extremamente difícil trabalhar com threads usando só wait e
		// notify. Prefira usar as classes de java.util.concurrent.
		try { Thread.sleep (2000); } catch (InterruptedException ex) {}
		System.out.println ("Acordando uma ou mais threads");
		synchronized (lock) {
			lock.notifyAll();
		}
		try { thr1.join(); } catch (InterruptedException ex) {}
		try { thr2.join(); } catch (InterruptedException ex) {}
		try { thr3.join(); } catch (InterruptedException ex) {}
	}
}
Criado 11 de junho de 2010
Ultima resposta 14 de jun. de 2010
Respostas 9
Participantes 4