我写了一个 Java ME 益智游戏。我这样编写代码:有一个线程在应用程序启动时启动,一旦游戏开始,就会有第二个线程在无限循环中运行——主游戏循环。有一次,第二个线程看起来像这样:

public void run() {
    init();
    while (shouldIRun) {
        updateGameState();
        checkUserInput();
        updateGameScreen(getGraphics());
        this.flushGraphics();
    }
}

迷人的。这个线程只是运行并运行,直到我想杀死它,当我将 boolean 值 shouldIRun 设置为 false 时,它​​就会优雅地退出。

但后来我意识到我想要更多。该游戏是一款益智游戏,玩家可能会做出错误的 Action 然后卡住。发生这种情况时,他们可以启动一个表单并选择“重新启动级别”选项。然后设置一个标志 restartLevel,当无限循环进入 updateGameState() 方法时,关卡重新启动。但这对我来说就像一场赌博——我不想开始更改主循环中正在使用的对象的变量,以防出现并发问题,尽管我可能是偏执狂。在实践中,我意识到我想做的事情非常清楚:我只是想暂停无限循环线程,将变量更改为我想要的,然后重新启动。

我通过以下方式做到了这一点:
public void run() {
    init();
    while (shouldIRun) {

        if (shouldIWait) {
            iAmWaiting=true;
            while (shouldIWait) { };
            iAmWaiting=false;
        }

        updateGameState();
        checkUserInput();
        updateGameScreen(getGraphics());
        this.flushGraphics();
    }
}

我在想的是以下内容。如果我现在想从“基本”线程“暂停”第二个线程,我只需将 shouldIWait 变量设置为 true,然后循环直到我注意到 iAmWaiting 变量也是 true。我现在肯定知道第二个线程已经暂停,我确切地知道它在哪里暂停,“暂停”实际上是指“暂时陷入无限循环”。我现在可以使用一些基本变量,重新启动关卡,并大致解决问题,然后最后将 shouldIWait 设置回 false 并重新开始。

我的问题是:这对我来说很好用,但有点混杂。是否有一些完全标准的方式来做可能是常见的事情——在给定的点暂停一个线程,然后在我准备好时重新启动它,这比我正在做的更好吗?特别是我怀疑“将 java 放入无限循环”可能不是一件聪明的事情。

最佳答案

通常,这就是您使用 Object.wait()Object.notify() 的目的。

有几种方法可以根据您的情况实现它,但这里有一个简单的例子:

Object monitor = new Object();
volatile boolean done = false, wait = false;

/* Running on one thread: */
public void run() {
    synchronized(monitor) {
        while(!done) {
            while(wait) {
                monitor.wait();
            }
            gameLogicAndStuff();
        }
    }
}

/* Running on another thread: */
public void showResetForm() {
    wait = true;
    synchronized(monitor) {
        actuallyShowResetForm();
        wait = false;
        monitor.notifyAll();
    }
}

10-08 02:20