为什么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 { 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 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)。 睡眠时间为1200毫秒的工人在哪里? 实际上,如果我用1000毫秒替换1200毫秒,那么这个工作者也打印1行…是的,只有一行。 奇怪的…

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

在Windows 7 64位上使用JRE 7 Update 11运行此程序。

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

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

编辑:
要certificateSwingWorker线程是一个守护进程线程,只需添加一行代码来测试它:

 System.out.println("I am thread with " + ms + " sleep in iteration " + i + ": " + t.getName() + " (" + t.getId() + ")"); // **** added System.out.println("Daemon?: " + Thread.currentThread().isDaemon()); 

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

 thread.setDaemon(true); 

您将看到SwingWorker在守护程序线程中执行,而在Java中,如果所有非守护程序线程都已完成,则JVM将终止。

如前所述,您可以使用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 { 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; } } 

您是否尝试过创建任何UI? 或者添加类似new Object().wait(); 在主要结束时,防止主线程退出?

我不完全确定是这种情况,但是没有任何实际的UI显示,我很确定swing工作者只是另一个线程,并且你没有配置任何作为守护程序线程,所以main启动它们,main完成,过程退出?