2013-03-15 146 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