【问题标题】:How to properly wait until ActionListener is executed?如何正确等待 ActionListener 执行?
【发布时间】:2014-03-19 10:55:15
【问题描述】:

我有一个简单、大小可变的井字游戏应用程序,它在不同机器上的工作方式不同。在我的笔记本电脑上,它像我想要的那样工作,在我的桌面上,它卡在实现ActionListenerButtonListener 类中。我很确定这是因为我使用while 循环等待执行操作的方式。这是有问题的代码sn-p。

public void playOneTurn(int player) {
    waiting = true;
    while (waiting) {
        // Do nothing, touchEvent will change waiting.
    }
}

我的意思是让这个方法简单地等待一个有效的位置被选中,然后waiting 被翻转到ButtonListener

    class ButtonListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("TOUCHEVENT");

        for (i = 0; i < size; i++)
            for (j = 0; j < size; j++)
                if (e.getSource() == cells[i][j]) {
                    if (model[i][j] == 'e') {
                        cells[i][j].setText("");
                        currentSpot[0] = i;
                        currentSpot[1] = j;
                        if (count % 2 == 0) {
                            cells[i][j].setBackground(Color.GREEN);
                            cells[i][j].setIcon(X_MARK);
                            model[i][j] = 'x';
                            count++;
                            waiting = false;
                        } else {
                            cells[i][j].setBackground(Color.CYAN);
                            cells[i][j].setIcon(O_MARK);
                            model[i][j] = 'o';
                            count++;
                            waiting = false;

                        }

                    } else {
                        System.out.println("Hey, you can't move there silly!");
                    }
                }
    }
}

我对线程一无所知,但我相信ButtonListener 正在启动一个线程,并且由于我等待它的方式,使用while 循环,线程永远不会停止让其余的我的代码在某些机器上运行。

我在使用 while 循环等待事件来翻转布尔值时是否出错,如果是,我将如何正确等待它?

【问题讨论】:

  • 启动一个单独的线程来运行playOneTurn,并将Thread.sleep() 放入你的循环中,以节省cpu 周期
  • 不同的行为可能是因为waiting可能没有声明为volatile:当一个线程改变它的值时,另一个线程不一定查看新值(除非变量是 volatile 或存在同步形式)。但正如已经指出的那样:您在那里所做的事情被称为“忙着等待”,通常是一种不好的做法,应该用synchronizedwait()notifyAll() 代替。

标签: java multithreading swing awt actionlistener


【解决方案1】:

不要简单地使用while(true) 循环。它将占用您的 CPU 使用率。请改用synchronization。创建一个private final Object 并在其上调用wait()。在此之前将此对象的引用发送到 MessageListener。当您在 MessageListener 中的操作完成后,您可以在其上调用notify()

还要照顾Spurious wakeups

【讨论】:

  • 感谢您的回答。我不知道如何正确添加synchronization 代码。首先,我不知道我是否将代码插入到正确的位置,其次我不知道如何处理 InterruptedException,或者为什么会抛出它。我知道让while 循环不断寻找布尔值是有问题的。
【解决方案2】:

您应该重新设计您的应用程序。完全没有必要等待。除非有一些事件(即用户输入)触发了这种变化,否则应用程序的整个状态不会改变。对于井字游戏尤其如此。除非某些用户输入以允许的方式更改了状态,否则您要等待的条件不会变为真。因此,您可以在条件可能变为真的地方检查侦听器内部的条件。然后立即做出反应。

因此,您应该实现对事件做出反应、更改应用程序状态并返回的侦听器。下一个状态转换将在下一个事件发生时发生,而不是在此之前的单个 CPU 周期。如果您想独立于用户生成的事件(即动画)进行更改,请使用Timer,它将生成适当的事件。

【讨论】:

  • 如果计算机玩家在自己的线程中计算最佳移动,这可能不是真的。
  • @Marco13:除了tic tac toe 不需要这样的计算这一事实之外:这在回合制游戏中毫无意义,每个玩家都必须等待对方才能开始考虑轮到他/她/自己。甚至在可以进行这种背景计算的游戏中,即 AI 不必等待轮到人类:嗯,这意味着不需要等待轮到人类……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-12-05
  • 2019-08-27
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
  • 1970-01-01
  • 2016-04-10
相关资源
最近更新 更多