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 vo开发者_JAVA技巧id 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?
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();
}
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 anonymousThread
object, create an anonymousRunnable
. 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
Thread
s orRunnable
s.
Use Semaphores.
- Start the threads at the beginning of the program.
- Each run() method should loop continuously.
- At the top of the loop, acquire() the appropriate semaphore (red/blue).
- When a winner is detected release() the appropriate semaphore.
What's wrong with creating another instance of the Thread? Reusing Threads is nasty, can lead to really weird behaviour and generally shouldn't be done.
Besides the repetition of your code (There is only 1 line difference in the Threads, right?), you can simply implement the Thread as an inner class. This way you don't have to use an anonymous instance and you can recreate and start is as many times as you want.
You should definetly think about adding the color as a parameter to this Thread!
(I'm pretty sure there's a compiler error in here, but you should get 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;
}
}
}
}
Have a look at java's wait()
and notify()
methods. Here is a tutorial on them.
Threads can be paused and resumed using the following functions :
- suspend() = for pausing
- resume() = for resuming
Implementation:
threadObject.suspend();
threadObject.resume();
But i think these functions are deprecated. Not sure though.
精彩评论