2013-03-15 111 views
1

我在java swing上運行的項目有2個用於計數的按鈕(啓動/停止)。java線程在運行多線程時不會中斷

當我點擊開始按鈕。有一個線程正在運行(Thread-0),然後單擊停止按鈕「Thread-0」消失,但是當我多次單擊開始按鈕時。有許多線程,例如Thread-5,Thread-6,.. Thread-10正在運行。

問題: 如果點擊開始,然後停止計數是好的。但點擊開始多次這是不正確的計數。

啓動按鈕

private void btnStartActionPerformed(java.awt.event.ActionEvent evt) {   
    start(); 
    btnStart.setEnabled(false); 
    btnStop.setEnabled(true); 
} 

停止按鈕

private void btnStopActionPerformed(java.awt.event.ActionEvent evt) {    
    isEnable = false; 
    btnStop.setEnabled(false); 
    btnStart.setEnabled(true); 
}  

start()方法:

isEnable = true; 
Thread refreshPlan = new Thread() { 
    @Override 
    public void run() { 
     while(isEnable) { 
      try { 
       sleep(CYCLE_TIME * 1000); 
       PLAN += 1; 
       planValue.setText(String.valueOf(PLAN)); 
      } catch (InterruptedException ex) { 
       //ignore 
      } 
     } 
    }; 
    }; 
    refreshPlan.start(); 

燦我在開始按鈕中多次點擊時只運行單線程? 有什麼建議嗎?謝謝。

對不起我的英語不好。

+0

爲更好的幫助,儘快發佈一個[SSCCE](http://sscce.org/),簡短,可運行,可編譯, 但是關於在Swing中的Concurency問題已回答 – mKorbel 2013-03-15 08:01:02

回答

5

有這裏四季顯著的問題:

  • 除非isEnable被聲明爲volatile變量,有沒有保證一個線程的寫入將在另一個線程中看到
  • 同樣,您可以訪問PLAN計數器(這是非常有名的 - 請關注Java命名約定)是不安全的。你不妨考慮使用AtomicInteger
  • 您正在從您的額外線程更改UI。你不能這麼做 - 在Swing(和大多數UI)中,對UI組件的所有訪問都必須在負責該UI的線程上完成。有關更多詳細信息,請參閱Swing concurrency tutorial
  • 由於您只檢查isEnabled每秒一次,因此可以在此期間停止並啓動多個線程......從而導致多個線程同時處於活動狀態。這可能會影響您的計數。

您可能會發現最好使用每秒觸發一次的javax.swing.Timer,並檢查它是否意味着要做任何事情。那樣的一切都可以在UI線程上。

+0

@Phonbopit使用[SwingWorker](http://stackoverflow.com/a/15166242/714968),Swing Timer被指定爲延遲,可管理的endles循環,而不是用於工作線程級聯Swing – mKorbel 2013-03-15 07:25:16

+0

+1,但不包括Swing Timer – mKorbel 2013-03-15 07:25:59

+0

@mKorbel:「級聯工作線程」是什麼意思?我提出了一個無限循環,有效地 - 每秒鐘,它* *增加計數器或不增加,基於狀態。我寧願這樣做,而不是使用SwingWorker的額外線程。將所有內容保存在單個線程中可以減少各種錯誤的可能性。 – 2013-03-15 07:30:07

-1

啓動方法正在實例化新的Thread(),這就是爲什麼每次你點擊它時,都會給生活帶來新的線索。

聲明Thread refreshPlan類變量,然後在啓動方法把所有的代碼在單向

if(refreshPlan == null || !refreshPlan.isAlive()){ 
//ur existing code to instantiate new thread. 
} 
+0

壞主意 - 這是一個競爭條件,因爲在檢查之前,線程可能還活着*,然後立即停止。 – 2013-03-15 07:43:08

+0

好吧,我認爲在檢查時沒有足夠的滯後和耗時,而且這種邊緣情況可能發生在有條件流程的任何地方。 – Ankit 2013-03-15 08:08:11

+0

不,這樣的競爭條件只有在你不考慮它們時纔會發生。 'Thread.isAlive()'應該幾乎*總是*用於診斷目的,而不是用於啓動另一個線程的邏輯。 – 2013-03-15 08:09:22