Problemas ao usar o wait ();

9 respostas
D

Galera, estou fazendo um jogo da memória. Estava com problema em deixar imagens clicadas à mostra. Estava usando o Thread.sleep(); mas tava dando problema. Resolvi tentar usar o wait(); ta funcionando de boa, mas no eclipse ocorre o seguinte erro:

Exception in thread AWT-EventQueue-0 java.lang.IllegalMonitorStateException

at java.lang.Object.wait(Native Method)

at Memoria2$TratarEventos.actionPerformed(Memoria2.java:84)

at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)

at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)

at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)

at javax.swing.DefaultButtonModel.setPressed(Unknown Source)

at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)

at java.awt.Component.processMouseEvent(Unknown Source)

at javax.swing.JComponent.processMouseEvent(Unknown Source)

at java.awt.Component.processEvent(Unknown Source)

at java.awt.Container.processEvent(Unknown Source)

at java.awt.Component.dispatchEventImpl(Unknown Source)

at java.awt.Container.dispatchEventImpl(Unknown Source)

at java.awt.Component.dispatchEvent(Unknown Source)

at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)

at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)

at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)

at java.awt.Container.dispatchEventImpl(Unknown Source)

at java.awt.Window.dispatchEventImpl(Unknown Source)

at java.awt.Component.dispatchEvent(Unknown Source)

at java.awt.EventQueue.dispatchEvent(Unknown Source)

at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)

at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)

at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)

at java.awt.EventDispatchThread.pumpEvents(Unknown Source)

at java.awt.EventDispatchThread.pumpEvents(Unknown Source)

at java.awt.EventDispatchThread.run(Unknown Source)

o código é esse:

public void actionPerformed (ActionEvent evento) { for (int i = 0; i < botao.length; i++) { if (evento.getSource() == botao[i]) { botao[i].setIcon(icones[i]); temp = new Timer (2500, this); temp.start(); if (but1 ==-1) { but1 = i; jogada++; } else { but2 = i; jogada++; } try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } }

Pelo que percebi, o wait () se refere ao Timer, correto?

9 Respostas

S

O método wait() deve ser chamado dentro de um contexto sincronizado, isto é:

synchronized(this){
  try{
   this.wait();
 }catch(InterruptedException ie){}
}

Isto ocorre porque um Thread não pode chamar um método wait() de um objeto a menos que obtenha o bloqueio desse objeto.

D

Com esse código o programa executa e trava.

L

Oi,

Você está utilizando o interrupted em algum lugar?

Tchauzin!

D

não

E

wait e notify não devem ser chamados se você não souber exatamente o que está fazendo.
São primitivas muito arriscadas se você não souber usá-las direito (threads, wait e notify são o equivalente do “goto” em programação estruturada).
Normalmente, você deve evitar usar tais coisas, e usar rotinas do pacote java.util.concurrent.

D

Eis aí o código na integra:

import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.Timer;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JPanel;
import javax.swing.ImageIcon;
import java.util.Random;
import javax.swing.JOptionPane;
public class Memoria2 extends JFrame {
	JButton [] botao;
	ImageIcon [] icones;
	ImageIcon padrao;
	Random r = new Random();
	JButton memoria;
	Timer temp;
	public Memoria2 (int quant,int t1, int t2 , int h, int l) {
		super ("Jogo da Memória");
		icones = new ImageIcon[quant];
		Random r = new Random();
		padrao = new ImageIcon(this.getClass().getResource("img/pokebola.gif"));
		padrao.setImage(padrao.getImage().getScaledInstance(110, 114, 200));
		botao = new JButton[quant];
		setIconImage(padrao.getImage());
		for (int i = 0; i < ((botao.length)/2); i++) {
			String aux="img/"+Integer.toString(i)+".gif";
			icones[i] = new ImageIcon(this.getClass().getResource(aux));
			icones[i].setImage(icones[i].getImage().getScaledInstance(110, 114, 200));
		}
		for (int i = (botao.length)/2; i < botao.length; i++) {
			icones[i] = icones[i-((botao.length)/2)];
		}
		for (int i = 0; i < botao.length; i++) {
			int pos = r.nextInt(botao.length);
			ImageIcon img = icones[i];
			icones[i] = icones[pos];
			icones[pos] = img;
		}
		for (int i = 0; i < botao.length; i++) {
			botao[i] = new JButton(padrao);
		}
		setLayout (new BorderLayout());
		JPanel panel = new JPanel();
		panel.setLayout(new GridLayout (t1,t2,0,0));
		for (int i = 0; i < botao.length; i++){
			panel.add(botao[i]);
		}
		add(panel,BorderLayout.CENTER);
		TratarEventos te = new TratarEventos ();
		for (int i = 0; i < botao.length; i++) {
			botao[i].addActionListener(te);
		}
		setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		setSize(h,l);
		setResizable(false);
		setLocationRelativeTo(null);
		setVisible(true);
	}
	public void resetarImagens(int a, int b) {
		botao[a].setIcon(padrao);
		botao[b].setIcon(padrao);
	}
	private class TratarEventos implements ActionListener {
		int jogada;
		int but1, but2, fim;
		public void actionPerformed (ActionEvent evento) {
			for (int i = 0; i < botao.length; i++) {
				if (evento.getSource() == botao[i]) {
					botao[i].setIcon(icones[i]);
					temp = new Timer (1000, this);
					temp.start();
					if (but1 ==-1) {
						but1 = i;
						jogada++;
					}
					else {
						but2 = i;
						jogada++;
					}
					try {
						wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
				}
			}
			if (jogada == 2) {
				if (but1 == but2) {
					resetarImagens(but1, but2);
					but1 = -1;
					but2 = -1;
					jogada = 0;
				}
				else 
					if (botao[but1].getIcon() != botao[but2].getIcon()) {
						resetarImagens(but1, but2);
						but1 = -1;
						but2 = -1;
						jogada = 0;
					}
					else {
						botao[but1].setEnabled(false);
						botao[but2].setEnabled(false);
						fim +=2; 
						but1 = -1;
						but2 = -1;
						jogada = 0;
					}
			}
			if (fim == botao.length)
				JOptionPane.showMessageDialog(null, "Fim de Jogo!", 
				"Fim de Jogo", JOptionPane.INFORMATION_MESSAGE);
		}
	}
	public static void main(String[] args) {
		String op = JOptionPane.showInputDialog ("Informe o grau de dificuldade: " +
				""+"\n 1 - Fácil"+"\n 2 - Médio"+"\n 3 - Dificil");
		if (op.equals("1"))
			new Memoria2(20, 4,5, 600, 520);
		else if (op.equals("2"))
			new Memoria2(30, 5,6, 710, 630);
		else if (op.equals("3"))
			new Memoria2(40, 5,8,920,630);
	}
}

Se alguem puder testar meu código, eu agradeço
(trocar o caminho da imagem)

L

entanglement:
wait e notify não devem ser chamados se você não souber exatamente o que está fazendo.
São primitivas muito arriscadas se você não souber usá-las direito (threads, wait e notify são o equivalente do “goto” em programação estruturada).
Normalmente, você deve evitar usar tais coisas, e usar rotinas do pacote java.util.concurrent.

Oi,

Acho que não é bem assim né!

Tchauzin!

E

Toda vez que achei código com wait e notify para fazer manutenção, vi que havia algum problema de implementação (já que é uma arte conseguir usar adequadamente tais métodos), e que as coisas poderiam ser feitas de maneira mais simples usando-se algum conceito de nível mais alto, implementado em alguma classe de java.util.concurrent.

S

Ao chamar wait(), o Thread libera os bloqueios do objeto e aguarda eternamente até que uma chamada notify ou notifyAll seja feita no objeto monitor. Ao ver superficialmente o seu código, vi que você fez uma chamada wait() para aguardar até que uma determinada operação ou método sejam realizados. Assim, você deve notificar o Thread que está aguardando, com uma chamada notify() ou notifyAll() imediatamente após o termino da última linha de instrução do método ou operação a serem executados.

Criado 29 de novembro de 2009
Ultima resposta 30 de nov. de 2009
Respostas 9
Participantes 4