我写了一个Java ME益智游戏。我是这样写代码的:有一个线程在应用程序启动时启动,一旦游戏开始,还有第二个线程在无限循环中运行——主游戏循环。第二个线程看起来是这样的,有一点:
public void run() {
init();
while (shouldIRun) {
updateGameState();
checkUserInput();
updateGameScreen(getGraphics());
this.flushGraphics();
}
}
太好了。当我将布尔shouldIRun
设置为false时,这个线程一直运行,直到我想杀死它,然后它就优雅地退出了。
但后来我意识到我想要更多。这个游戏是一个益智游戏,玩家可能会做出错误的动作,然后陷入困境。当这种情况发生时,他们可以启动一个窗体并选择"重新启动级别"选项。然后设置一个标志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();
}
}
也许终止线程并用新级别启动新线程会更简单。
如果有一些信息需要从一个级别传递到下一个级别,也许您可以重构代码,以便首先收集一些一般信息,然后为每个级别启动一个线程。(我所说的启动线程,是指使用线程池。)
我不认为你现在忙于等待的做法是邪恶的。正如Ben Flynn在评论中提到的,您可以通过在Thread.sleep(50).