How to implement the wait(); statement properly?

Tags: , ,



I’m getting an issue when I’m trying to make a tic tac toe game. The Issue that I’m coming across is presented when I’m trying to use a wait(); statement in order to pause the game so the player is able to look at who won the game and what the winning squares are, however when I try to run this little chunk of code right here:

            wait(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

It gives me this error code right here:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at GameCode.restart(GameCode.java:264)
    at GameCode.xWins(GameCode.java:245)
    at GameCode.check(GameCode.java:171)
    at GameCode.actionPerformed(GameCode.java:70)
    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.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$500(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(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)

It describes it to be an IllegalMonitorStateException, however I tried using throw to resolve this problem but it still continues to give me this error. Any solutions out there? For reference here is my code if you need to see any other info:

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class GameCode implements ActionListener {
    
    Random random = new Random();
    JFrame frame = new JFrame();
    JPanel title_panel = new JPanel();
    JPanel button_panel = new JPanel();
    JLabel textfield = new JLabel();
    JButton[] buttons = new JButton[9];
    boolean player1_turn;
    
    
    
    
    GameCode() {
        
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500,500);
        frame.getContentPane().setBackground(new Color(0,0,0));
        frame.setLayout(new BorderLayout());
        frame.setVisible(true);
        
        textfield.setBackground(new Color(25,25,25));
        textfield.setForeground(new Color(25,255,0));
        textfield.setFont(new Font("TimesRoman", Font.BOLD,75));
        textfield.setHorizontalAlignment(JLabel.CENTER);
        textfield.setText("Tic Tac Toe");
        textfield.setOpaque(true);
        title_panel.setLayout(new BorderLayout());
        title_panel.setBounds(0,0,800,100);
        
        button_panel.setLayout(new GridLayout(3,3));
        button_panel.setBackground(new Color(150,25,25));
        
        for(int j = 0; j < 9; j++ ) {
            
            buttons[j] = new JButton();
            button_panel.add(buttons[j]);
            buttons[j].setFont(new Font("Ink Free", Font.BOLD,120));
            buttons[j].setFocusable(false);
            buttons[j].addActionListener(this);
            
        }
        
        
        title_panel.add(textfield);
        frame.add(title_panel, BorderLayout.NORTH);
        frame.add(button_panel);
        
        Turnone();
        
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        
        for (int i = 0; i < 9; i++) {
            
            if(arg0.getSource()==buttons[i]) {
                if(player1_turn) {
                    if(buttons[i].getText()=="") {
                        buttons[i].setForeground(new Color(255,0,0));
                        buttons[i].setText("X");
                        player1_turn=false;
                        textfield.setText("O turn");
                        check();
                    }
                } else {
                    if(buttons[i].getText()=="") {
                        buttons[i].setForeground(new Color(0,0,255));
                        buttons[i].setText("O");
                        player1_turn=true;
                        textfield.setText("X turn");
                        check();
                    }
                }
            }
        }
    }//Creating the Buttons the player will interact with
    
    public void Turnone() {
        
        for(int i=0; i<9;i++) {
            buttons[i].setEnabled(false);
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        for(int i=0; i<9;i++) {
            buttons[i].setEnabled(true);
        }
        
        if(random.nextInt(2)==0) {
            
            player1_turn = true;
            textfield.setText("X turn");
            
        } else {
            
            player1_turn = false;
            textfield.setText("O Turn");
            
        }
        
    }//Using a random int to decide which player will go first
    
    public void check() {
        //X Wins
        
        if(
                (buttons[0].getText()=="X") &&
                (buttons[1].getText()=="X") &&
                (buttons[2].getText()=="X") 
                ) {
            xWins(0,1,2);
        }
        if(
                (buttons[3].getText()=="X") &&
                (buttons[4].getText()=="X") &&
                (buttons[5].getText()=="X") 
                ) {
            xWins(3,4,5);
        }
        if(
                (buttons[6].getText()=="X") &&
                (buttons[7].getText()=="X") &&
                (buttons[8].getText()=="X") 
                ) {
            xWins(6,7,8);
        }
        if(
                (buttons[0].getText()=="X") &&
                (buttons[3].getText()=="X") &&
                (buttons[6].getText()=="X") 
                ) {
            xWins(0,3,6);
        }
        if(
                (buttons[1].getText()=="X") &&
                (buttons[4].getText()=="X") &&
                (buttons[7].getText()=="X") 
                ) {
            xWins(1,4,7);
        }
        if(
                (buttons[2].getText()=="X") &&
                (buttons[5].getText()=="X") &&
                (buttons[8].getText()=="X") 
                ) {
            xWins(2,5,8);
        }
        if(
                (buttons[0].getText()=="X") &&
                (buttons[4].getText()=="X") &&
                (buttons[8].getText()=="X") 
                ) {
            xWins(0,4,8);
        }
        if(
                (buttons[2].getText()=="X") &&
                (buttons[4].getText()=="X") &&
                (buttons[6].getText()=="X") 
                ) {
            xWins(2,4,6);
        }
        //O Wins
        
        if(
                (buttons[0].getText()=="O") &&
                (buttons[1].getText()=="O") &&
                (buttons[2].getText()=="O") 
                ) {
            oWins(0,1,2);
        }
        if(
                (buttons[3].getText()=="O") &&
                (buttons[4].getText()=="O") &&
                (buttons[5].getText()=="O") 
                ) {
            oWins(3,4,5);
        }
        if(
                (buttons[6].getText()=="O") &&
                (buttons[7].getText()=="O") &&
                (buttons[8].getText()=="O") 
                ) {
            oWins(6,7,8);
        }
        if(
                (buttons[0].getText()=="O") &&
                (buttons[3].getText()=="O") &&
                (buttons[6].getText()=="O") 
                ) {
            oWins(0,3,6);
        }
        if(
                (buttons[1].getText()=="O") &&
                (buttons[4].getText()=="O") &&
                (buttons[7].getText()=="O") 
                ) {
            oWins(1,4,7);
        }
        if(
                (buttons[2].getText()=="O") &&
                (buttons[5].getText()=="O") &&
                (buttons[8].getText()=="O") 
                ) {
            oWins(2,5,8);
        }
        if(
                (buttons[0].getText()=="O") &&
                (buttons[4].getText()=="O") &&
                (buttons[8].getText()=="O") 
                ) {
            oWins(0,4,8);
        }
        if(
                (buttons[2].getText()=="O") &&
                (buttons[4].getText()=="O") &&
                (buttons[6].getText()=="O") 
                ) {
            oWins(2,4,6);
        }
    
    }//Stating all the win conditions for the game
    
    public void xWins(int a, int b, int c) {
        buttons[a].setBackground(Color.GREEN);
        buttons[b].setBackground(Color.GREEN);
        buttons[c].setBackground(Color.GREEN);
        
        for(int i=0; i<9;i++) {
            buttons[i].setEnabled(false);
        }
        
        textfield.setText("X Wins!");
        
        restart();
    }//When Player X wins
    
    public void oWins(int a, int b, int c) {
        buttons[a].setBackground(Color.GREEN);
        buttons[b].setBackground(Color.GREEN);
        buttons[c].setBackground(Color.GREEN);
        
        for(int i=0; i<9;i++) {
            buttons[i].setEnabled(false);
        }
        textfield.setText("O Wins!");
        
        restart();
    }//When Player O wins 
    
    public void restart() { 
        
        try {
            wait(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        
    }
    
    
    
}//GameCode

Answer

You are doing too much on the event thread including checking for wins and waiting. So the following changes will work in a pinch.

First, put the entire body of the actionPerformed method in a separate thread.

    @Override
    public void actionPerformed(ActionEvent arg0) {
        new Thread(()-> {
        for (int i = 0; i < 9; i++) {
            
            if(arg0.getSource()==buttons[i]) {
                if(player1_turn) {
                    if(buttons[i].getText().equals("")) {
                        buttons[i].setForeground(new Color(255,0,0));
                        buttons[i].setText("X");
                        player1_turn=false;
                        textfield.setText("O turn");
                        check();
                    }
                } else {
                    if(buttons[i].getText().equals("")) {
                        buttons[i].setForeground(new Color(0,0,255));
                        buttons[i].setText("O");
                        player1_turn=true;
                        textfield.setText("X turn");
                        check();
                    }
                }
            }
        }
        }).start();
    }

Then it will be safe to use sleep in your restart method. You could also use a Swing Timer but it is still important to not do too much processing on the event thread.

public void restart() {
   try {
       Thread.sleep(2000);
   } catch (InterruptedException ie) {
   }
   System.out.println("Waking up");
  
}

But your overall approach has some issues when it comes to painting and handling events. You should check out the Java Tutorials for more on painting and event processing.



Source: stackoverflow