2013-02-15 54 views
8

我想用SwingWorker尝试一些想法,因为我没有用太多。相反,我遇到了一个问题,我无法弄清楚什么是错的。为什么SwingWorker会意外停止?

下面是一个简短SSCCE演示这个问题(我知道这里的人喜欢SSCCEs):

import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 

public class SwingWorkerTest 
{ 
    public static void main (String[] args) 
    { 
     SwingUtilities.invokeLater (new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       new MySwingWorker (500).execute(); 
       new MySwingWorker (900).execute(); 
       new MySwingWorker (1200).execute(); 
      } 
     }); 
    } 
} 

class MySwingWorker extends SwingWorker<Void, Void> 
{ 
    private int ms; 

    public MySwingWorker (int ms) 
    { 
     this.ms = ms; 
    } 

    @Override 
    protected Void doInBackground() 
    { 
     Thread t = Thread.currentThread(); 

     for (int i = 0; i < 50; i++) 
     { 
      try 
      { 
       Thread.sleep (ms); 
      } 
      catch (InterruptedException e) 
      { 
       e.printStackTrace(); 
      } 

      System.out.println ("I am thread with " + ms + " sleep in iteration " + i + ": " + t.getName() + " (" + t.getId() + ")"); 
     } 

     return null; 
    } 
} 

所以我的程序应该创建3个SwingWorkers打印屏幕上的线,然后睡眠指定的毫秒数然后再次打印该行并再次入睡等。我从Swing的主题中创建了SwingWorker,因为否则它们甚至不会启动。

所以预期输出是:

I am thread with 500 sleep in iteration 0: SwingWorker-pool-1-thread-1 (15) 
I am thread with 900 sleep in iteration 0: SwingWorker-pool-1-thread-2 (16) 
I am thread with 500 sleep in iteration 1: SwingWorker-pool-1-thread-1 (15) 
I am thread with 1200 sleep in iteration 0: SwingWorker-pool-1-thread-3 (17) 
I am thread with 500 sleep in iteration 2: SwingWorker-pool-1-thread-1 (15) 
I am thread with 900 sleep in iteration 1: SwingWorker-pool-1-thread-2 (16) 
I am thread with 500 sleep in iteration 3: SwingWorker-pool-1-thread-1 (15) 
I am thread with 1200 sleep in iteration 1: SwingWorker-pool-1-thread-3 (17) 
I am thread with 500 sleep in iteration 4: SwingWorker-pool-1-thread-1 (15) 
I am thread with 900 sleep in iteration 2: SwingWorker-pool-1-thread-2 (16) 
I am thread with 500 sleep in iteration 5: SwingWorker-pool-1-thread-1 (15) 
I am thread with 500 sleep in iteration 6: SwingWorker-pool-1-thread-1 (15) 
I am thread with 900 sleep in iteration 3: SwingWorker-pool-1-thread-2 (16) 
I am thread with 1200 sleep in iteration 2: SwingWorker-pool-1-thread-3 (17) 
I am thread with 500 sleep in iteration 7: SwingWorker-pool-1-thread-1 (15) 
............. 

等,共150行(3名工人×50次迭代针对每个)

相反,输出I得到的是:

I am thread with 500 sleep in iteration 0: SwingWorker-pool-1-thread-1 (15) 
I am thread with 900 sleep in iteration 0: SwingWorker-pool-1-thread-2 (16) 
I am thread with 500 sleep in iteration 1: SwingWorker-pool-1-thread-1 (15) 

就是这样。只有3行。之后程序退出。从try catch块的任何地方都没有堆栈跟踪。

1)。睡眠时间为1200ms的员工在哪里?实际上,如果我用1000毫秒替换1200毫秒,那么这位工作人员也打印1行......是的,只有一行。奇怪...

2)。为什么工人停下来? (我没有得到150行东西)

我跑这个程序使用JRE 7 Update 11在Windows 7 64位

PS:我很确定the bug mentioned here在这个JRE版本中得到修复,因为我在控制台上得到了2个不同的值(15和16)作为线程ID。这是我怀疑的第一件事。

回答

9

我相信你需要展示一个可视化的Swing顶层窗口,以保持Swing事件线程的活跃。否则,程序将因缺少非守护线程而关闭。

编辑:
要证明的SwingWorker线程是守护线程,只需添加一行代码来测试它:

System.out.println("I am thread with " + ms + " sleep in iteration " 
    + i + ": " + t.getName() + " (" + t.getId() + ")"); 

// **** added 
System.out.println("Daemon?: " + Thread.currentThread().isDaemon()); 
+0

+1是否'SwingWorker'的'doInBackground'在非守护线程执行? – 2013-02-15 18:15:28

+1

@ Eng.Fouad:请看编辑。编辑:或者像你所做的那样查看源代码。 1+给你的答案! – 2013-02-15 18:36:16

3

您是否尝试过创建任何UI?或者在主的末尾放置new Object().wait();之类的东西,以防止主线程退出?

我不是完全确定这种情况,但没有任何实际的用户界面显示,我很确定摆动工作人员只是另一个线程,并且你没有配置任何守护程序线程,所以主要启动它们,主要完成,并且进程退出?

9

如果你看一下SwingWorker类的源代码771线(Java SE 7中):

thread.setDaemon(true); 

您将看到SwingWorker是一个守护线程中执行,并在Java的JVM将如果被终止所有非守护线程都已完成。

+4

废话,你们是对的。 SwingWorkers作为守护线程运行。这甚至没有跨过我的想法。谢谢你,StackOverflow,你总是有一切的答案:D。 – 2013-02-15 18:23:30

4

如前所述,您可以使用UI来保持线程活着。

或者,你可以做的是使用SwingWorker#get(或任何防止主线程终止的)等待线程完成。通过这样做,您将获得预期的输出。这里是修改过的代码,它可以做你想做的。

import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 
import java.util.concurrent.ExecutionException; 

public class SwingWorkerTest 
{ 
    public static void main (String[] args) 
    { 
     final MySwingWorker w1 = new MySwingWorker (500), 
     w2 = new MySwingWorker (900), 
     w3 = new MySwingWorker (1200); 
     SwingUtilities.invokeLater (new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       w1.execute(); 
       w2.execute(); 
       w3.execute(); 
      } 
     }); 

     try{ 
      // you can replace the code in this block 
      // by anything that keeps the program from 
      // terminating before the threads/SwingWorkers. 
      w1.get(); 
      w2.get(); 
      w3.get(); 
     }catch(InterruptedException e){ 
      System.err.println("InterruptedException occured"); 
     }catch(ExecutionException e){ 
      System.err.println("InterruptedException occured"); 
     } 

    } 
} 

class MySwingWorker extends SwingWorker<Void, Void> 
{ 
    private int ms; 

    public MySwingWorker (int ms) 
    { 
     this.ms = ms; 
    } 

    @Override 
    protected Void doInBackground() 
    { 
     Thread t = Thread.currentThread(); 

     for (int i = 0; i < 50; i++) 
     { 
      try 
      { 
       Thread.sleep (ms); 
      } 
      catch (InterruptedException e) 
      { 
       e.printStackTrace(); 
      } 

      System.out.println ("I am thread with " + ms + " sleep in iteration " + i + ": " + t.getName() + " (" + t.getId() + ")"); 
     } 

     return null; 
    } 
} 
+0

谢谢,这很有帮助。 – 2013-02-15 18:29:59

+0

的确很有帮助。 1+ – 2013-02-15 18:37:20

+0

你值得拥有+1 :) – 2013-02-15 18:41:14