2013-05-30 75 views
0

我試圖讓我的Java應用程序關閉,但線程仍處於打開狀態。無法在退出時關閉所有AWT線程

當使用默認的Windows x按鈕單擊關閉時,一切都很好(可能是由於EXIT_ON_CLOSE?) - 但是當我使用編程按鈕時,它掛在thread.join()上。

更糟糕的是,窗口處理得很好,所以用戶會認爲它已關閉 - 但仍有幾個AWT線程保持打開狀態。我的主線程正在等待一個ID爲20的線程,但我不知道如何獲取線程ID。

有沒有人有任何建議?

這裏是我的退出代碼:

public synchronized void stop() { 
    running = false; 
    frame.dispose(); 
    WindowEvent wev = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING); 
    Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev); 
    try { 
     if (server != null) { 
      server.exit(); 
     } 
     client.exit(); 
     thread.join(); 
     new Thread(){ 
      public void run() { 
       System.exit(0); 
      } 
     }.start(); 
    } catch (InterruptedException e) { 
     Thread.currentThread().interrupt(); 
     e.printStackTrace(); 
     System.exit(1); 
    } 
} 

,這裏是線程開放後的出口:

threads-eclipse

,這裏是我的run()方法的內容:

public void run() { 
    requestFocus(); 
    while (running) { 
     getTimer().tick(); 
     if (System.currentTimeMillis() - getTimer().getSecond() > 1000) { 
      // every second, add a second, print fps and mod title with fps 
      getTimer().accumulateSecond(); 
      //System.out.println(getTimer().returnFPS()); 
      frame.setTitle(title + " | " + getTimer().returnFPS()); 
      getTimer().resetTick(); 
      ticker++; 
     } 
     while (getTimer().getDelta() >= 1) { 
      // every time delta goes greater than one, update and supertick 
      update(); 
      getTimer().superTick(); 
     } 
     if (getTimer().getFPS() > 100) { 
      try { 
       Thread.sleep(5); 
      } catch (Exception e) { 
       System.err.println("Sleeping failed: " + e); 
      } 
     } 
     render(); 
     if (ticker > 30) { 
      ticker = 0; 
      getTimer().hourTick(); 
     } 

    } 
    stop(); 
} 
+0

移動'System.exit(0)'臨時紗線之上加入'()'工作完全關閉它,但我懷疑它是線程安全的? – gossfunkel

+0

請問這是什麼原因,在這裏,是否可能是錯誤的, – mKorbel

+0

您在上面的'stop()'方法所在的同一個類中的內部* Thread類中顯示的run()方法是什麼? 'run()'中是否有其他調用調用'synchronized'方法? – Nate

回答

0

更新:

看到更多的代碼後,我很確定你的問題是你從一個線程調用stop()(這是​​)。在stop()的內部,您可以撥打thread.join(),它會嘗試等待thread實例完成其run()方法。設置running標誌會導致run()退出其while循環,但該方法中的最後一行代碼是對stop()的另一個調用。如果這是您向我們展示的方法相同stop()方法,那麼您有一個死鎖

stop()調用你的run()方法內部將永遠無法進入的方法,因爲第一個線程還在裏面stop(),正在等待run()完成(它永遠不會,因爲它在等待能夠打電話和輸入stop())。僵局。

您必須從run()中刪除對stop()的調用,或者找到另一種方法來重新修改代碼。


我不擔心識別特定的線程ID。擔心讓所有線程正確完成。

首先,Thread#join()不是停止一個線程。它等待它完成。您正在做的其他事情必須使/允許thread實例完成其run()方法。

我看到那些可能這樣做的唯一事情是設置

running = false; 

是您的thread對象檢查其run()方法裏面那個標誌?例如:

public void run() { 
    while (isRunning()) { 

     // do some work 
     Thread.sleep(delay); 
    } 
} 

其中isRunning()會回到你的running變量的值?

現在,我不能說沒有看到更多的代碼。但是,您可能選擇實現isRunning()這樣的:

public synchronized boolean isRunning() { 
    return running; 
} 

如果你這樣做,那麼有一個問題。主線程將獲得您向我們顯示的stop()方法中的鎖。然後它將進入thread.join()調用,此時它開始等待工作線程。如果工作線程然後調用在同一個鎖上同步的isRunning(),則isRunning()將被阻塞,因爲由於主線程位於stop()內部,鎖已被佔用。

如果thread對象試圖調用任何其它​​方法從類,它的代碼,你向我們展示可能會出現同樣的基本問題。長話短說,我們需要看到更多的代碼(thread變量代表的線程正在運行什麼)。但是,你可能在這裏陷入僵局。

Read more here about stopping a thread gracefully

+0

'run()'方法直接檢查'running',是的,整個事情都在裏面。我相信它正在等待某個子線程關閉,但我無法識別任何線程。沒有太多的同步方法,沒有太多的資源可能變得不同步。 – gossfunkel

+0

除非您向我們展示代碼(在run()'方法內部運行的代碼傳遞給'thread'對象),否則我們無法幫助您。除了我已經提出的猜測之外,你所展現的不足以調試問題。 – Nate

+1

@gossfunkel,如果這是從'run()'調用的相同'stop()'方法,那麼這就是你的問題。 'stop()'是'synchronized',所以'thread'將不能進入'stop()',因爲另一個線程已經在**'stop()'裏面了,等待'thread.join() '。 – Nate