【问题标题】:How to pause / resume Java Threads如何暂停/恢复 Java 线程
【发布时间】:2011-08-02 06:35:21
【问题描述】:

我正在用 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 再次获胜时,程序崩溃了。

我调查了一下,发现你不能启动一个线程两次,因为你不能。

我将如何暂停线程,然后在需要时重新启动它?

【问题讨论】:

  • 感谢提出一个引起很多兴趣和答案的问题。 +1

标签: java multithreading swing animation tic-tac-toe


【解决方案1】:

在您重播动画线程的情况下,您可能希望:

  • 将线程封装为自己的Runnable对象,例如与其创建匿名的Thread 对象,不如创建一个匿名的Runnable
  • 然后简单地重新创建线程并启动它:

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

    顺便说一句,在编写 Threads 或 Runnables 时,您可能需要考虑 Swing 不是线程安全的。

【讨论】:

    【解决方案2】:

    使用Semaphores

    1. 在程序开始时启动线程。
    2. 每个 run() 方法都应该连续循环。
    3. 在循环的顶部,acquire() 适当的信号量(红色/蓝色)。
    4. 当检测到获胜者时,释放() 适当的信号量。

    【讨论】:

    • 我不认为Semaphore 正是他在这里所需要的……我认为这只是多次运行线程的某种方式。
    • +1 - 跳出框框思考。 FWIW,我也会看看 CountdownLatch 和 CyclicBarrier。
    【解决方案3】:

    看看 java 的 wait()notify() 方法。 Here 是关于它们的教程。

    【讨论】:

      【解决方案4】:

      您可以简单地创建一个新线程并在需要时运行它。但不管怎样,我都会使用 Swing Timer 来制作动画,因为它更简单、更安全,因为您不必担心意外踩到 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();
         }
      

      【讨论】:

      • 这比使用Thread 更安全,但如果你愿意的话,你可以用EventQueue.invokeLater() 包围你的电话。
      • @Nathan Moos:这正是javax.swing.Timer 的工作原理。它使用TimerQueue 的共享静态实例,这是一个使用一个线程管理所有计时器的内部类。
      【解决方案5】:

      创建另一个线程实例有什么问题?重用线程很讨厌,会导致非常奇怪的行为,通常不应该这样做。

      除了代码的重复(线程中只有 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;
                  }
              }
          }
      }
      

      【讨论】:

      • 这是不好的做法,应该是Runnable恕我直言。
      【解决方案6】:

      可以使用以下函数暂停和恢复线程:

      • suspend() = 暂停
      • resume() = 用于恢复

      实施:

      threadObject.挂起();

      threadObject.resume();

      但我认为这些功能已被弃用。不过不确定。

      【讨论】:

        猜你喜欢
        • 2015-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-08
        • 2012-07-13
        • 1970-01-01
        相关资源
        最近更新 更多