2011-04-15 110 views
0

我正在使用Java中的應用程序來更新每秒的結果,直到它停止。在30秒鐘內,它會每秒調用一組特定的方法,然後在接下來的30秒內調用另一組方法,然後再次調用第一組,然後依此類推。由於我希望能夠在任何時候停止並重新啓動在後臺執行的計算,因此我創建了一個GUI和幾個按鈕來啓動和停止新線程,以及一種顯示結果的方法每一秒。Java線程問題

我遇到的問題是,一旦新線程啓動,我不能切換回GUI,直到它完成,並且由於線程將繼續前進,直到我告訴它停止,我最終不能退出無限循環。我可以通過將GUI放在它自己的線程中來解決這個問題,以便兩個線程同時運行?如果是這樣,我將如何從GUI內部做到這一點?

我正在使用多個類,所以我不想發佈不相關的東西。

public class GUI extends javax.swing.JFrame implements Runnable{ 
    Graphics g; 
    Threads thread = new Threads(); 
    private void startButtonActionPerformed(java.awt.event.ActionEvent evt) { 
     thread.run() 
    } 
    [..] 
    private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) { 
     thread.stop() 
    } 
} 
public class Threads implements Runnable{ 
boolean opened=false; 
road first = new road(); 
public void run() { 
    opened=true; 
    first.standardInitialization(); 
    while(opened){ 
     for(int i=0; i<30 && opened; i++){ 
      try { 
       first.redLightAction(); 
       System.out.println("cars: " + first.firstLight.cars); 
       Thread.sleep(1000); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(Threads.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
     for(int i=0; i<30 && opened; i++){ 
      try { 
       first.greenLightAction(); 
       second.greenLightAction(); 
       System.out.println("cars: " + first.firstLight.cars); 
       Thread.sleep(1000); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(Threads.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
    } 
} 
public void stop(){ 
    opened=false; 
} 

} 
+0

請發表相關的代碼。 – MByD 2011-04-15 21:44:00

+0

郵政編碼。如果確實創建了一個新線程來執行該工作,它不應該影響GUI線程。 – 2011-04-15 21:44:15

+0

這篇文章將回答您的問題,併爲您提供可幫助您的解決方案:[併發性](http://download.oracle.com/javase/tutorial/uiswing/concurrency/index.html) – 2011-04-15 21:46:24

回答

3

是的,你的GUI應該在它自己的線程中。

您尚未使用主題。您正在使用實現Runnable的自定義類。 Runnable!=線程。要做到這一點,而不是:

Thread thread = new Thread(new Threads()); 

當你想運行它,用

thread.start(); // not thread.run()!! 

請注意,我傳遞您的Runnable到一個真正的主題。我會建議將你的線程類重命名爲更具體的東西。

所以,現在你已經設置了它的方式,你只是在與GUI相同的線程中運行Runnable。通過上面的代碼,你將會產生一個新的執行線程。

+0

它應該模擬兩條街道之間的交叉點。每秒鐘的紅綠燈,隨機數的汽車等待綠燈。每秒鐘的交通燈都是綠色的,一定數量的汽車離開了。我應該做的是監控每個交通燈的車輛數量。 – Skates 2011-04-15 21:48:09

+0

我不關心業務邏輯,我想看看你如何管理線程的實際代碼。如果你的GUI在這個其他線程正在執行時被鎖定,你要麼沒有正確地使用線程,要麼另一個線程以某種方式阻止你的GUI(共享資源或者某個東西)。 – Brad 2011-04-15 21:49:54

+0

我已經發布了與我一直存在的問題相關的代碼,請你看看嗎? – Skates 2011-04-15 22:26:07

2

GUI在事件調度線程上更新。由於您的界面沒有響應,EDT線程沒有執行任何工作。這可能是因爲:

  • 工作背景沒有被在一個單獨的線程中完成的,但實際上在美國東部時間
  • 你成功地創建一個新的後臺線程,而不是讓它異步運行,你是等待它完成。

您無法在另一個線程上運行GUI - 擺動必須在由系統創建的線程上運行 - 事件調度線程。

編輯:增加了更多的代碼。您需要thread.start()而不是thread.run()。 start方法實際上會導致新線程開始執行(然後調用run()方法)。當您直接調用run()方法時,它只是一個常規方法調用,並在調用(GUI)線程上執行,因此UI被阻止。

+0

我相當確定這是第一個選項。我的線程是由GUI創建的,我假設這意味着它不會與GUI線程同時運行。我怎麼能解決這個問題? – Skates 2011-04-15 21:52:05

2

是的,任何非gui活動(特別是長時間運行的任務)都應該在新線程上運行。

參見「EDT」,Swing的GUI線程的描述:http://en.wikipedia.org/wiki/Event_dispatching_thread

你可以使用SwingUtilities類的靜態方法,以方便EDT和其他線程之間切換... http://download.oracle.com/javase/6/docs/api/javax/swing/SwingUtilities.html

見的invokeLater(Runnable接口),isEventDispatchThread(),和其他人,讓你開始...

1

Swing不是線程安全的。使用名爲Event Dispatch Thread的東西進行擺動(請參閱mdma post以獲得快速介紹),並且您可以找到一個很好的教程here。 Swing並不是要與線程一起運行,但可以使用Event Dispatch Thread的線程對幾乎所有可以執行的任何事情進行建模,除了(大點)以外,它不會是併發的。

1

確切的解決方案取決於您必須做什麼的確切細節以及是否需要更新GUI。

從我讀到的內容中,我可以建議你實現一種遊戲循環。因爲我知道你想模擬流量並將其呈現給用戶。然後,這樣的遊戲循環將在其每次迭代中首先進行所有計算並更新對象,最終在屏幕上顯示新狀態。這不是一個簡單的任務,我怕你應該熟悉Java中代碼的併發性和同步性。

public void run() 
{ 
    long startTime = System.currentTimeMillis(); 
    long currTime = startTime; 
    isRunning = true; 

    while(isRunning) 
    { 
     long elapsedTime = System.currentTimeMillis() - currTime; 
     currTime += elapsedTime; 
     update(elapsedTime); 
     gameRender(); 
     paintScreen(); 
     try 
     { 
      Thread.sleep(1000); 
     }catch(InterruptedException ex) 
     { 
      Logger.getLogger(GamePlayPanel.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
} 

你必須像上面一個在你的類實現Runnable的骨架,然後創建一個線程給它的類作爲參數,最後你開始吧。

關於遊戲建設的更多閱讀可以在http://www.brackeen.com/這傢伙發表了一本關於Java遊戲的精彩書籍,強烈推薦。

EDIT1: 從代碼中我發現你創建的線程很好,但是你應該使用線程的啓動方法啓動它,而不是運行。 --->爲什麼由@Brad解釋。

祝你好運,博羅。