Как приостановить / возобновить потоки Java
Я делаю программу Tic Tac Toe на java, потому что я изучаю java, и я думал, что простой проект будет отличным местом для начала. Это мой код до сих пор:
public class Start {
public static void main(String[] args) {
GameTicTacToe gameTicTacToe = new GameTicTacToe();
gameTicTacToe.windowBirth();
}
}
и
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();
}
}
}
Это мой вопрос, когда игрок выигрывает, например, игрок 1 (синий), он воспроизводит анимацию (мигает синей доской). Но когда игрок 1 снова выигрывает, программа аварийно завершает работу.
Я немного заглянул в него и обнаружил, что вы не можете запустить поток дважды, потому что ты просто не можешь.--3-->
Как я могу приостановить поток, а затем перезапустить его, когда мне нужно?
6 ответов
вы можете просто создать новый поток и запустить его при необходимости. Но независимо от этого, я бы сделал анимацию с помощью таймера Swing, поскольку это проще и безопаснее, так как вам не нужно беспокоиться о пагубных прерывистых сбоях от случайного перехода на поток Swing, EDT.
, например,
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();
}
в вашем случае, когда поток анимации воспроизводится, вы можете:
- Инкапсулируйте поток как свой собственный
Runnable
объект, например, вместо создания анонимногоThread
объект, создать анонимнуюRunnable
. -
затем просто воссоздайте поток и запустите его:
public void winnerAnimation(int b) { ... if (b == 1) { animationThread = new Thread(winnerBlue); animationThread.start(); } else { animationThread = new Thread(winnerRed); animationThread.start(); } }
кстати, вы можете рассмотреть тот факт, что Swing не является потокобезопасным при написании вашего
Thread
илиRunnable
s.
использовать семафоры.
- запустить потоки в начале программы.
- каждый метод run() должен постоянно петли.
- в верхней части цикла приобретите () соответствующий семафор (красный/синий).
- при обнаружении победителя release () соответствующий семафор.
что не так с созданием другого экземпляра потока? Повторное использование потоков неприятно, может привести к действительно странному поведению и вообще не должно быть сделано.
помимо повторения вашего кода (есть только 1 разность строк в потоках, верно?), вы можете просто реализовать поток как внутренний класс. Таким образом, вам не нужно использовать анонимный экземпляр, и вы можете воссоздать и запустить столько раз, сколько хотите.
Вы должны определенно подумать о добавлении цвет как параметр этой нити!
(Я уверен, что здесь есть ошибка компилятора, но вы должны понять, что я имею в виду.)
// 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;
}
}
}
}
посмотрите на java wait()
и notify()
методы. здесь является учебником по ним.
потоки можно приостановить и возобновить, используя следующие функции:
- suspend () = на пауза
- resume() = для возобновления
реализация:
threadObject.приостановить();
threadObject.резюме();
но я думаю, что эти функции являются устаревшими. Не уверенный хотя.