Erro com wait() - Thread

6 respostas
ECO2004

Olá, pessoal!

Tem um problema ocorrendo quando eu chamo wait() no meu objeto. Eu descrevo o erro mais abaixo!

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

public class SharedBufferMain
{
	public static void main(String[] args)
	{
		ExecutorService executorService = Executors.newCachedThreadPool();
		
		SharedBuffer sharedBuffer = new SharedBuffer();
		
		FutureTask<Integer> futureTask1 = new FutureTask<Integer>(new Produtor(sharedBuffer));
		FutureTask<Integer> futureTask2 = new FutureTask<Integer>(new Consumidor(sharedBuffer));
		
		executorService.execute(futureTask1);
		executorService.execute(futureTask2);
		
		executorService.shutdown();
	}
}
import java.util.Random;
import java.util.concurrent.Callable;

public class Produtor implements Callable<Integer> 
{
	SharedBuffer sharedBuffer;
	private static Random r = new Random();
	
	public Produtor(SharedBuffer sharedBuffer)
	{
		this.sharedBuffer = sharedBuffer;
	}
	
	public Integer call() throws Exception 
	{
		System.out.printf("%-40s%s\t\t%s\n%-40s%s\n\n", "Posição", "Vetor", "Valor",
				"---------", "------\t\t-------");
		
		for(int posicao = 0; posicao < 100; posicao++ )
		{
			sharedBuffer.setValor(posicao, r.nextInt(100));
		}		
		
		return 1;
	}
}
import java.util.concurrent.Callable;

public class Consumidor implements Callable<Integer>
{	
	SharedBuffer sharedBuffer;
	
	public Consumidor(SharedBuffer sharedbuffer)
	{
		this.sharedBuffer = sharedBuffer;
	}
	
	public Integer call() throws Exception 
	{
		for(int posicao = 0; posicao < 100; posicao ++)
		{
			sharedBuffer.getValor(posicao);
		}
		
		return null;
	}
}
public interface ProdutorConsumidor 
{
	public void setValor(int posicao, int valor);
	public int getValor(int posicao);
}
public class SharedBuffer implements ProdutorConsumidor 
{	
	public static final int tamanhoBuffer = 10;
	public static int buffer [] = new int[tamanhoBuffer];
	public boolean turn;
	public int valor;
	
	public int getValor(int posicao)
	{
		synchronized(buffer)
		{		
			while(!turn)
			{
				try
				{
					buffer.wait();
				}
				
				catch(InterruptedException e)
				{
					e.printStackTrace();
				}	
			}

			valor = buffer[posicao%tamanhoBuffer];
			turn = false;
			buffer.notify();
			
			return valor;
		}
	}
	
	public void setValor(int posicao, int valor)
	{
		synchronized(buffer) 
		{
			while(turn)
			{
				try
				{
					buffer.wait();
				}
				
				catch(InterruptedException e)
				{
					e.printStackTrace();
				}
			}
			
			buffer[posicao%tamanhoBuffer] = valor;
			turn = true;
			buffer.notify();
			
			//System.out.printf("\n%s %d%d\n%s\n", posicao, posicao%tamanhoBuffer, valor);
			System.out.println(posicao+"                                         "+
					posicao%tamanhoBuffer+"               "+valor);
		}
	}
}

O que acontece é que, no segundo loop (posicao = 1) em Produtor ele verifica turn para ver de quem é a vez. Mesmo o produtor tendo o objeto do monitor, ele não pode produzir duas vezes (o intuito é produzir, consumir...sucessivamente no vetor circular). Quando ele tenta dar um wait() no objeto (buffer), aparece a exceção:

int[](Object).wait() line: 485 [local variables unavailable]
SharedBuffer.setValor(int, int) line: 16	
Produtor.call() line: 21
Produtor.call() line: 1	
FutureTask$Sync.innerRun() line: not available [local variables unavailable]	
FutureTask<V>.run() line: not available [local variables unavailable]	
ThreadPoolExecutor$Worker.runTask(Runnable) line: not available	
ThreadPoolExecutor$Worker.run() line: not available [local variables unavailable]	
Thread.run() line: not available [local variables unavailable]

Alguém poderia me fazer o favor de ajudar?
Não vejo erro em dar um wait no objeto, para que outra thread possa obter o objeto do monitor.

6 Respostas

R

vc precisa dar um wait na thread…

ViniGodoy

Tem algo estranho aí. Cadê o texto da exception? Você está rodando no debug? Pois esse stack aí está completamente sem informação.

E a forma que você dá o wait() e o notify() também está estranho. Não por causa da variável, pois isso está certo, o wait() e o notify() tem que ser dado sobre o monitor. Mas, vc está aparentemente usando a mesma variável para controlar 2 pontos de sincronização independentes. Por exemplo, o seu nofify() debaixo vai atuar sobre aquele wait() logo acima dele.

ViniGodoy

Agora que vi. Threads é um assunto de Java avançado, portanto, vou mover seu tópico, ok?

ECO2004

Ok…descuple-me por não ter colocado no Java avançado…

Com relação ao monitor, é somente um objeto atuando mesmo. Poderia ser “this”, mas quero se que seja um objeto int [], que é onde serão colocados os valores. Não quero que uma thread entre em Produtor e outra em Consumidor. Por isso, uso o mesmo objeto em ambos os monitores.
Bem, mesmo estando dentro de um try/catch, nada é lançado no console. Somente aparece o rastro da pilha quando uso o debug.
Que nem disse, no segundo loop, o programa “trava” e é bem no wai.

Ainda não vi o erro…

ECO2004

ViniGodoy:
Tem algo estranho aí. Cadê o texto da exception? Você está rodando no debug? Pois esse stack aí está completamente sem informação.

E a forma que você dá o wait() e o notify() também está estranho. Não por causa da variável, pois isso está certo, o wait() e o notify() tem que ser dado sobre o monitor. Mas, vc está aparentemente usando a mesma variável para controlar 2 pontos de sincronização independentes. Por exemplo, o seu nofify() debaixo vai atuar sobre aquele wait() logo acima dele.

Vini…então…o que fiz é o seguinte [me corrija se eu estiver errado…]

Quando uma thread entra na classe Produtor, ele é enviado à classe SharedBuffer através do for. Ao chegar, ele entra no método set(i), depois de obter o objeto de monitor. Bem, se conseguiu, verifica se pode continuar, em turn. Se não puder, é dado um wait na thread que chamou o método. Esse wait libera o objeto de monitor e coloca a thread em espera.

Um segunda thread entra em Consumidor. Pelo for, ela entra em get() da classe SharedBuffer. Verifica se pode obter o objeto de monitor. Depois, verifica se é a sua vez (turn). Depois, se for, ela faz o que tiver de fazer e dá um notify, colocando a outra thread em espera no estado de bloqueado. Agora, se a thread em Consumidor tentar novamente entrar em get() para consumir, ela adormecerá.

A primeira thread, agora bloqueada, pode tentar novamente obter o objeto de monitor. Irá conseguir e tenta produzir…and so on…

Bem, essa é a minha lógica. Se alguém vir algo errado no código, me dê um toque.
Realmente, nada é lançado no console. Para ver algum erro, somente com debug!

ECO2004

Alguém??

Criado 17 de julho de 2011
Ultima resposta 18 de jul. de 2011
Respostas 6
Participantes 3