2012-02-03 88 views
4

我寫了一個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

回答

1

通常情況下,這是你會用什麼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

1

也許這將只是簡單的殺死線程並啓動一個新的與新的水平。

如果有需要從一個級別進行到下的一些信息,也許你可以重構你的代碼,你先收集一些一般信息,然後開始爲每個級別一個線程。 (和通過啓動一個線程,我的意思是使用一個線程池。)

我不認爲你正在與忙等待做什麼是邪惡的。正如Ben Flynn在評論中提到的那樣,您可以通過循環Thread.sleep(50)來使其等待半忙。

+0

該程序的以前版本用於執行此操作,但需要傳遞各種參數,我對某些看起來可能會發生的參考循環有點擔心 - 然後我意識到我可以按照上面的建議進行操作取而代之。 – 2012-02-04 12:35:21