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:

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), he plays the animation (Blue panel flashes). But when player 1 wins again, the program crashes.

I looked into it a bit and found that you cannot run the thread twice because you simply cannot.

How can I pause a thread and then restart it when I need to?

+6
source share
6 answers

You can simply create a new thread and start it if necessary. But regardless of this, I would do the animation using the Swing timer, since it is simpler and safer, since you do not need to worry about the disruptive intermittent crashes from accidentally switching to the Swing stream, EDT.

For instance,

  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(); } 
+6
source

In your case, when the animation stream plays, you can:

  • Encapsulate a stream as its own Runnable , for example. instead of creating an anonymous Thread object, create an anonymous Runnable .
  • Then just re-create the stream and run it:

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

    By the way, you might think that Swing is not thread safe when writing your Thread or Runnable s.

+3
source

Use Semaphores .

  • Run threads at the beginning of the program.
  • Each run () method should work continuously.
  • At the top of the loop, acquire () the corresponding semaphore (red / blue).
  • When the winner detects release () the corresponding semaphore.
+3
source

What happened to creating another Thread instance? Reusing Threads is nasty, can lead to really weird behavior and should not be done at all.

Besides repeating your code (there is only 1 line difference in threads, right?), You can simply implement Thread as an inner class. This way you do not need to use an anonymous instance, and you can recreate and run as many times as you want.
You should definitely consider adding color as a parameter to this stream!

(I'm sure there is a compiler error here, but you should understand what I mean.)

 // other stuff here... public void winnerAnimation(int b) { for (int i = 0; i < gridButton.length; i++) { gridButton[i].setEnabled(false); } if (b == 1){ new WinnerThread(Color.BLUE).start(); }else{ new WinnerThread(Color.RED).start(); } } class WinnerThread extends Thread { private Color color; public WinnerThread(Color c) { color = c; } public void run() { for (int a = 0; a < 4; a++) { for (int i = 0; i < gridButton.length; i++) { gridButton[i].setBackground(color); } 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; } } } } 
+2
source

Take a look at the java wait() and notify() methods. Here is a tutorial on them.

+1
source

Streams can be paused and resumed using the following functions:

  • suspend () = to pause
  • resume () = to resume

Implementation:

threadObject pause () ;.

threadObject resume () ;.

But I think these features are outdated. Not sure though.

0
source

Source: https://habr.com/ru/post/885584/


All Articles