Error Monitor Thread

olá, está ocorrendo o seguinte erro na execução de uma thread:


java.lang.IllegalMonitorStateException
	at java.lang.Object.wait(Native Method)
	at core.UpdateStatusWorker.run(UpdateStatusWorker.java:17)

Alguem poderia me auxiliar neste erro? A linha 17 do meu código é a do wait(5000) e a classe é está.


public class UpStatus extends Thread {
	Worker worker;
	boolean running = true;
	boolean permission = true;

	UpStatus(Worker worker) {
		this.worker = worker;
	}

	public void run() {
		try {
			while (this.running) {
				this.worker.statusSend();
				while (this.permission) {
					wait(5000);
				}
				this.permission = true;
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void setPermission(boolean permission) {
		this.permission = permission;
	}
}

Você só pode chamar o wait em blocos sincronizados. Se você só quer dar uma pausa, use o Thread.sleep no lugar.

Eu estou precisando fazer dois acordadores para esta thread UpStatus. Eu tenho uma thread externa que deverá acordar a UpStatus e além disso se esta externa não conseguir acordar a UpStatus deve acordar sozinha após 5 ou 10s.

Só que não estou conseguindo resolver este problema. Pode me auxiliar?

Primeiro de tudo. Threads são uma coisa, objetos são outra. Até que você entenda bem esse conceito, fica mesmo difícil modelar o seu problema.
Tente não fazer suas classes estenderem thread, e organize bem o seu negócio.

Outra coisa, a classe Thread representa só um disparador de thread. Ser filho de thread, não é uma thread. Uma thread pode percorrer vários objetos, bem diferentes do qual ela foi disparada.

Agora que isso ficou claro, vamos ao seu problema. Antes de eu te ajudar, me diga, o que seu código tem que fazer? Qual problema você está tentando resolver?

o Problemas é este, simples mas não estou entendendo. :smiley:


package acordandoThreadExterna;

public class ProdutorTrabalho {

	Trabalhador w;
	int valor;
	int id = 1;

	public static void main(String[] args){
		ProdutorTrabalho prod = new ProdutorTrabalho();
		prod.inicializa();
	}
	public void inicializa() {
		for (int i = 0; i < 5; i++) {
			this.w = new Trabalhador(this.id++, this);
			this.w.start();
			this.produz();
		}
	}

	public void produz() {
		for (int i = 0; i < 10; i++) {
			valor = 5 + (int) (Math.random() * 40);
			this.w.recebe(valor);
		}
	}

	public void recebeStatus(int t, int status) {
		System.out.println("Recebi Status do Trabalhador: " + t
				+ " com tamanho da fila: " + status);
	}

}

package acordandoThreadExterna;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Trabalhador extends Thread {

	ProdutorTrabalho ger;
	UpStatus control;
	BlockingQueue<Integer> work;
	int valor;
	int id;

	public Trabalhador(int id, ProdutorTrabalho ger) {
		this.id = id;
		this.ger = ger;
		this.control = new UpStatus(this);
		this.control.start();
		this.work = new LinkedBlockingQueue<Integer>();
	}

	public void run() {
		try {
			this.valor = this.work.take();
			this.fibo(valor);
			this.atualiza();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void atualiza() {
		this.ger.recebeStatus(this.getID(), this.work.size());
	}

	public void recebe(int valor) {
		try {
			this.work.put(valor);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public int fibo(int n) {
		if (n <= 1)
			return n;
		return fibo(n - 1) + fibo(n - 2);
	}
	
	public void setID(int id) {
		this.id = id;
	}
	
	public int getID() {
		return this.id;
	}
}

package acordandoThreadExterna;

public class UpStatus extends Thread{
	
	Trabalhador worker;
	UpStatus (Trabalhador worker) {
		this.worker = worker;
	}
	public void run() {
		while (true) {
			this.worker.atualiza();			
			try {
				wait(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

O que sua aplicação precisa fazer?

Possui uma Classe ProduzTrabalho que ira produzir um numero qualquer para a classe Trabalhador, esta calcula o fibonacci deste numero. Alem disso esta classe deve enviar seu status para a classe ProduzTrabalho, para isso criei uma classe Thread UpStatus que é iniciada quando um Trabalhador é instanciado, esta UpStatus deve ser acordada em dois momentos, logo após que o Trabalhador acaba de calcular o fibonacci e a cada 5s.

O problema é que esta ocorrendo

java.lang.IllegalMonitorStateException at java.lang.Object.wait(Native Method) at core.UpdateStatusWorker.run(UpdateStatusWorker.java:17)

E eu nao estou descobrindo porque disso.

Ok. Então vc tem duas classes. A ProduzTrabalho, que é a produtora, e a Trabalhador, que é a consumidora.

Que status o trabalhor deve mandar para a classe produtora? E para que? Seria para dizer que ela está livre?

Então vamos ver se eu entendi:
a) A classe produtora deve produzir algo para o consumidor fazer a cada 5 segundos;
b) Se o consumidor informar que está ocioso, então um trabalho deve ser criado imediatamente;

É isso?

É isso mesmo. O status vai a informação do tamanho da fila. Eu preciso fazer um teste ainda no metodo recebeStatus, que verifica se esta com pouco trabalho ou nao, ou seja, se a fila dele for menor que 3 tenho que produzir mais para este trabalhador. Mas isso pode ser em um segundo momento, pois como vou fazer isso se o envio de status não está funcionando direito.

Veja como fica:
ProdutorTrabalho.java

import java.util.Random;

public class ProdutorTrabalho {
	private Trabalhador trabalhador;
	private Random random = new Random();

	public ProdutorTrabalho(Trabalhador trabalhador) {
		this.trabalhador = trabalhador;

		// Disparamos a thread produtora
		Thread produtor = new Thread(new Runnable() {
			public void run() {
				produzirTrabalho();
			}
		});
		produtor.setName(&quot;Produtor&quot;);
		produtor.start();
	}

	/**
	 * Método do produtor que recebe um status enviado pelo trabalhador. Isso faz com que o produtor gere trabalho
	 * imediatamente caso a fila seja &lt; 3.
	 */
	public synchronized void receberStatus(int tamFila) {
		System.out.print(&quot;Requisição de trabalho&quot;);
		if (tamFila &lt; 3) {
			System.out.println(&quot; aceita.&quot;);
			// Esse notify irá acordar o wait do método produzTrabalho.
			notifyAll();
		} else
			System.out.println(&quot;negada. Já há muito trabalho na fila.&quot;);
	}

	/**
	 * Gera um novo trabalho a cada 5 segundos, ou quando uma requisição for feita ao receber status.
	 */
	private synchronized void produzirTrabalho() {
		try {
			while (!Thread.interrupted()) {
				int nr = random.nextInt(40) + 10;
				System.out.println(&quot;Trabalho produzido: &quot; + nr);
				trabalhador.receberTrabalho(nr);
				// Aguarda 5s. O notifyAll() também libera o wait.
				wait(5000);
			}
		} catch (InterruptedException e) {
		}
	}
}[/code]

Trabalhador.java
[code]import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class Trabalhador {
	private BlockingDeque&lt;Integer&gt; trabalhos = new LinkedBlockingDeque&lt;Integer&gt;();
	private ProdutorTrabalho produtor;

	public void definirProdutor(ProdutorTrabalho produtor) {
		if (this.produtor != null)
			return;

		this.produtor = produtor;
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				trabalhar();
			}
		});
		thread.setName(&quot;Consumidor&quot;);
		thread.start();
	}

	/** Simplesmente insere um trabalho na fila.
	 * O método offer avisa o método take(), que desbloqueia a thread. */
	public void receberTrabalho(int trabalho) {
		trabalhos.offer(trabalho);
	}

	public void trabalhar() {
		try {
			System.out.println(&quot;Aguardando trabalho.&quot;);
			while (true) {
				// Aguardamos até que haja trabalho. 
				//O take() bloqueia a thread caso a fila esteja vazia.
				Integer trabalho = trabalhos.take();
				//Trabalhamos
				trabalhar(trabalho);
				//Avisamos o produtor que concluímos.
				produtor.receberStatus(trabalhos.size());
			}
		} catch (InterruptedException e) {
		}
	}

	private void trabalhar(Integer trabalho) {
		System.out.println(&quot;Trabalhando no Fibonacci(&quot; + trabalho + &quot;)...&quot;);
		System.out.println(&quot;Resultado: Fibonacci(&quot; + trabalho + &quot;) = &quot;
				+ fibo(trabalho));
	}

	private long fibo(int n) {
		if (n &lt;= 1)
			return n;
		return fibo(n - 1) + fibo(n - 2);
	}
}

Main.java

public class Main { public static void main(String[] args) { Trabalhador trabalhador = new Trabalhador(); ProdutorTrabalho produtor = new ProdutorTrabalho(trabalhador); trabalhador.definirProdutor(produtor); } }

Só um detalhe. Threads e sincronização está bem longe de ser um assunto de Java Básico. Por isso vou mover seu tópico para Java Avançado.

ahhh estou entendendo. Mas mais uma dúvida, no produtor você utiliza synchronized nos metodos, está sendo utilizado somente pelo motivo de que você está utilizando o wait e notify, correto? Caso tivesse mais um trabalhador, os métodos no trabalhador não deveriam ter o synchronized?

VLW

Não é necessário sincronizar os métodos do consumidor pois a sincronização é fornecida pela LinkedBlockingQueue.

No caso do produtor, sim, usamos sincronização por causa do wait e do notify.