Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pause / resume Java Threads

I am making a Tic Tac Toe Program in java because i am learning java and i thought a simple project would be a great place to start. This is my code so far:

public class Start {
    public static void main(String[] args) {
    GameTicTacToe gameTicTacToe = new GameTicTacToe();
    gameTicTacToe.windowBirth();

    }
}

And,

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

public class GameTicTacToe implements ActionListener {
    private int gridSize = 3;
    private JButton[] gridButton = new JButton[(gridSize * gridSize)];
    private JPanel grid = new JPanel(new GridLayout(gridSize, gridSize, 0, 0));
    private JFrame windowTicTacToe = new JFrame("Tisk, Task, Toes");
    private int[] gridButtonOwner = new int[(gridSize * gridSize)];
    private int turn = 1;
    private int HolerHor, HolerVer, HolerDia1, HolerDia2;

    Thread winnerBlue = new Thread() {
        public void run() {
            for (int a = 0; a < 4; a++) {
                for (int i = 0; i < gridButton.length; i++) {
                    gridButton[i].setBackground(Color.BLUE);
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                }
                for (int i = 0; i < gridButton.length; i++) {
                    gridButton[i].setBackground(Color.WHITE);
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                }
            }
            for (int i = 0; i < gridButton.length; i++) {
                gridButton[i].setEnabled(true);
                gridButtonOwner[i] = 0;
            }
        }
    };
    Thread winnerRed = new Thread() {
        public void run() {
            for (int a = 0; a < 4; a++) {
                for (int i = 0; i < gridButton.length; i++) {
                    gridButton[i].setBackground(Color.RED);
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                }
                for (int i = 0; i < gridButton.length; i++) {
                    gridButton[i].setBackground(Color.WHITE);
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                }
            }
            for (int i = 0; i < gridButton.length; i++) {
                gridButton[i].setEnabled(true);
                gridButtonOwner[i] = 0;
            }
        }
    };
    public void windowBirth() {
        for (int i = 0; i < gridButton.length; i++) {
            gridButtonOwner[i] = 0;
            gridButton[i] = new JButton("");
            gridButton[i].addActionListener(this);
            gridButton[i].setBackground(Color.WHITE);
            grid.add(gridButton[i]);
        }
        windowTicTacToe.setDefaultCloseOperation(3);
        windowTicTacToe.setLocation(400, 200);
        windowTicTacToe.setPreferredSize(new Dimension(400, 400));
        windowTicTacToe.add(grid);
        windowTicTacToe.pack();
        windowTicTacToe.setVisible(true);
    }
    public void actionPerformed(ActionEvent gridButtonClicked) {
        for (int i = 0; i < gridButton.length; i++) {
            if (gridButtonClicked.getSource() == gridButton[i]) {
                if (turn == 1) {
                    turn = 2;
                    gridButtonOwner[i] = 1;
                    gridButton[i].setBackground(Color.blue);
                    gridButton[i].setEnabled(false);
                } else {
                    turn = 1;
                    gridButtonOwner[i] = 2;
                    gridButton[i].setBackground(Color.red);
                    gridButton[i].setEnabled(false);
                }
            }
        }
        checkWinner();
    }
    public void checkWinner() {
        for (int a = 1; a < 3; a++) {
            HolerDia1 = a;
            HolerDia2 = a;
            for (int b = 0; b < gridSize; b++) {
                HolerHor = a;
                HolerVer = a;
                for (int c2 = 0; c2 < gridSize; c2++) {
                    HolerHor = (HolerHor * gridButtonOwner[((b * gridSize) + c2)])/ a;
                    HolerVer = (HolerVer * gridButtonOwner[((c2 * gridSize) + b)])/ a;
                }
                if (HolerHor == a || HolerVer == a) {
                    winnerAnimation(a);
                }
            }
            for(int h = 0;h < gridSize; h++){
                HolerDia1 = (HolerDia1 * gridButtonOwner[h * (gridSize + 1)]) / a;
                HolerDia2 = (HolerDia2 * gridButtonOwner[(h * (gridSize - 1)) + (gridSize - 1)]) / a;
            }
            if (HolerDia1 == a || HolerDia2 == a) {
                winnerAnimation(a);
            }
        }
    }
    public void winnerAnimation(int b) {
        for (int i = 0; i < gridButton.length; i++) {
            gridButton[i].setEnabled(false);
        }
        if (b == 1){
            winnerBlue.start();
        }else{
            winnerRed.start();
        }
    }
}

This is my question, When a player wins, for example Player 1 (Blue), it plays the animation (Flashing the board Blue). But when Player 1 wins again, the program crashes.

I looked into it a little and found that you can't start a thread twice because you just can't.

How would i go about pausing the thread, then restarting it when i need to?

like image 305
Joe C Avatar asked Apr 09 '11 22:04

Joe C


3 Answers

You could simply create a new Thread and run it when needed. But regardless of this, I'd do the animation using a Swing Timer as it's simpler and safer since you don't have to worry about pernicious intermittent crashes from accidently stepping on the Swing thread, the EDT.

For e.g.,

   public void myWinner(final Color flashColor) {
      int timerDelay = 300;
      new javax.swing.Timer(timerDelay , new ActionListener() {
         private static final int COUNTER_MAX = 5;
         int counter = 0;

         public void actionPerformed(ActionEvent e) {
            if (counter >= COUNTER_MAX) { // time to stop
               ((Timer)e.getSource()).stop();
               for (int i = 0; i < gridButton.length; i++) {
                  gridButton[i].setBackground(Color.white); // just to be sure
                  gridButton[i].setEnabled(true);
                  gridButtonOwner[i] = 0;
               }
            }
            Color bckgrndColor = (counter % 2 == 0) ? flashColor : Color.white;
            for (JButton button : gridButton) {
               button.setBackground(bckgrndColor);
            }
            counter++;
         }
      }).start();
   }
like image 130
Hovercraft Full Of Eels Avatar answered Sep 18 '22 11:09

Hovercraft Full Of Eels


In your case, where the animation thread is replayed, you may want to:

  • Encapsulate the thread as its own Runnable object, e.g. rather than creating an anonymous Thread object, create an anonymous Runnable.
  • Then simply recreate the thread and start it:

    public void winnerAnimation(int b)
    {
        ...
        if (b == 1)
        {
            animationThread = new Thread(winnerBlue);
            animationThread.start();
        }
        else
        {
            animationThread = new Thread(winnerRed);
            animationThread.start();
        }
    }
    

    BTW, you may want to consider the fact that Swing is not thread-safe when writing your Threads or Runnables.

like image 22
Nathan Moos Avatar answered Sep 18 '22 11:09

Nathan Moos


Use Semaphores.

  1. Start the threads at the beginning of the program.
  2. Each run() method should loop continuously.
  3. At the top of the loop, acquire() the appropriate semaphore (red/blue).
  4. When a winner is detected release() the appropriate semaphore.
like image 37
sourcedelica Avatar answered Sep 21 '22 11:09

sourcedelica