优雅地中断java线程

问题描述:

我写了一个Java ME益智游戏。我已经编写了这样的代码:有一个线程在应用程序启动时启动,并且一旦游戏启动,就会有第二个线程在无限循环中运行 - 主循环。第二个线程看起来像这样,在一个点上:优雅地中断java线程

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变量也是如此。我现在知道第二个线程已经暂停,并且我确切地知道它在哪里暂停,“暂停”的位置我实际上是指“暂时停留在无限循环中”。我现在可以用一些重要的变量来重复一遍,重新启动关卡,并且通常会将其排除,然后最终将shouldIWait设置为false,然后我们再次进入。

我的问题是:这工作得很好,对我来说,却是一个杂牌之嫌。有没有做什么,大概是常有的事的一些完全标准的方式 - 在一个给定的点暂停线程,然后重新启动它当我准备好,这比我在做什么好?特别是我怀疑“把java放在一个无限循环中”可能不是一件聪明的事情。

+0

你可以至少引入一个简短的线程睡觉while(shouldIWait) – 2012-02-03 23:25:47

+0

我看到 - 强制第二个线程睡觉,从而促使主线程回到行动? OK - 完成:-)但它仍然是一个混乱?我期待有人说“哦,只是使用t.pauseAtThisPointUntilISaySo()”或其他... – 2012-02-03 23:31:23

+0

是的,这就是为什么我没有提供它作为答案。 =)我猜想有人会和我一起讨论线程等待,但我认为我所建议的是某种自旋,有办法使用yielding和interrupts,这也可能是有效的。 – 2012-02-03 23:40:34

通常情况下,这是你会用什么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(); 
    } 
} 
+0

我会接受这个,因为它教会了我一些东西。不管我是否会执行它,都是另一回事:-)但是我可能会在一天结束时。 – 2012-02-04 12:36:10

也许这将只是简单的杀死线程并启动一个新的与新的水平。

如果有需要从一个级别进行到下的一些信息,也许你可以重构你的代码,你先收集一些一般信息,然后开始为每个级别一个线程。 (和通过启动一个线程,我的意思是使用一个线程池。)

我不认为你正在与忙等待做什么是邪恶的。正如Ben Flynn在评论中提到的那样,您可以通过循环Thread.sleep(50)来使其等待半忙。

+0

该程序的以前版本用于执行此操作,但需要传递各种参数,我对某些看起来可能会发生的参考循环有点担心 - 然后我意识到我可以按照上面的建议进行操作取而代之。 – 2012-02-04 12:35:21