【问题标题】:Why does SwingWorker stop unexpectedly?为什么 SwingWorker 会意外停止?
【发布时间】:2013-01-31 18:46:03
【问题描述】:

我想用SwingWorker 尝试一些想法,因为我没有用太多。相反,我遇到了一个问题,我不知道出了什么问题。

这里有一个简短的 SSCCE 演示了这个问题(我知道这里的人喜欢 SSCCE):

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 个 SwingWorker,它们在屏幕上打印一行,然后休眠指定的毫秒数,然后再次打印该行并再次休眠等。我从 Swing 的线程中创建 SwingWorkers,否则它们甚至都不会开始。

所以预期的输出是:

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 个 worker x 每个迭代 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:我很确定 the bug mentioned here 在此版本的 JRE 中已修复,因为我确实在控制台上打印了 2 个不同的值(15 和 16)作为线程 ID。这是我首先怀疑的。

【问题讨论】:

    标签: java multithreading swing concurrency swingworker


    【解决方案1】:

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

    编辑:
    为了证明 SwingWorker 线程是 Daemon 线程,只需添加一行代码进行测试即可:

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

    【讨论】:

    • +1 SwingWorkerdoInBackground 是否在非守护线程中执行?
    • @Eng.Fouad:请查看编辑。编辑:或按照您所做的那样查看源代码。 1+ 给你的答案!
    【解决方案2】:

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

    我不完全确定是这种情况,但是没有任何实际的 UI 显示,我很确定摇摆工作人员只是另一个线程,并且您没有将任何配置为守护线程,所以 main 启动它们,main 完成,然后进程退出?

    【讨论】:

      【解决方案3】:

      如果您查看 SwingWorker 类源代码 (Java SE 7) 的第 771 行:

      thread.setDaemon(true);
      

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

      【讨论】:

      • 天哪,你们是对的。 SwingWorkers 作为守护线程运行。这连我的想法都没有。谢谢你,StackOverflow,你总是有一切的答案:D。
      【解决方案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;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-05-01
        • 2023-01-22
        • 2013-12-26
        • 1970-01-01
        • 2012-03-22
        • 2012-10-18
        • 1970-01-01
        • 2012-03-24
        • 2015-05-11
        相关资源
        最近更新 更多