即使使用SwingWorker,Java GUI仍然会冻结

6

我正在尝试使用SwingWorker执行一个耗时的任务,并用结果更新JLabel:

button.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent arg0) {
        new SwingWorker<String, Void>() {

            @Override
            protected String doInBackground() throws Exception {
                return doCalculation();
            }

            protected void done() {
                try {
                    label.setText(get());
                } catch (InterruptedException e) {
                    System.out.println("thread was interrupted");
                } catch (ExecutionException e) {
                    System.out.println("there was an ExecutionException");
                }
            }

        }.execute();

    }

});

我可以无限制地点击按钮,Gui会保持响应,直到两个线程完成后Gui会冻结。如果我一次只运行一个线程,这个问题仍然存在。
如果有人能指出我是否不正确地使用了SwingWorker,或者是否存在其他我不知道的问题,我将非常感激。谢谢你的时间。 Ian
编辑: doCalculation()只是一个耗时的过程。
private String doCalculation() {
    for (int i = 0; i < 10000000; i++) {
        Math.pow(3.14, i);
    }
    return threads++ + "";
}

1
我没有看到您发布的代码有任何明显的问题,但我认为关键在于 doCalculation(); 方法中发生了什么。您能够发布这段代码吗? - Hovercraft Full Of Eels
1个回答

6

很抱歉,即使使用您的doCalculate()方法,我仍然无法重现您的问题。例如,这是我的sscce:

import java.awt.event.*;
import java.util.concurrent.ExecutionException;
import javax.swing.*;

public class FooGui {
   private static int threads = 0;

   private static void createAndShowUI() {
      final JLabel label = new JLabel("      ");
      JButton button = new JButton("Button");
      button.addActionListener(new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent arg0) {
            new SwingWorker<String, Void>() {

               @Override
               protected String doInBackground() throws Exception {
                  return doCalculation();
               }

               @Override
               protected void done() {
                  try {
                     label.setText(get());
                  } catch (InterruptedException e) {
                     System.out.println("thread was interrupted");
                  } catch (ExecutionException e) {
                     System.out.println("there was an ExecutionException");
                  }
               }
            }.execute();
         }
      });
      JPanel panel = new JPanel();
      panel.add(button);
      panel.add(label);

      JFrame frame = new JFrame("FooGui");
      frame.getContentPane().add(panel);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   private static String doCalculation() {
      for (int i = 0; i < 5000000; i++) {
         Math.pow(3.14, i);
      }
      return threads++ + "";
   }

   public static void main(String[] args) {
      java.awt.EventQueue.invokeLater(new Runnable() {

         @Override
         public void run() {
            createAndShowUI();
         }
      });
   }
}

你可以创建并发布自己的"简短,自包含,正确(可编译),示例"或SSCCE(请查看链接)。我敢打赌,在创建过程中,您可能会发现问题及其解决方案。如果是这样,请务必回到这里并告诉我们。
我知道这不是真正的答案,但没有办法在评论中发布代码。

1
谢谢你的帮助,我很感激。我在你的示例中也发现了同样的冻结问题,所以我进行了一些实验。从Eclipse/命令行运行会导致这个问题。我创建了一个可运行的JAR文件,它可以完美地运行。我正在运行64位Windows 7。我尝试了Ubuntu,似乎也解决了这个问题。再次感谢。 - Ian
我从来没有在Listener中看到过这个,我不确定该放在哪里......但是你的帖子,那可能是一个不错的方法,很好的例子,没有性能问题 +1 - mKorbel
1
@Ian:嗯,知道在特定情况下为什么会出现冻结仍然是很好的。也许这与线程过多有关。我听说在处理多个线程时,有时候不能使用SwingWorker,而需要使用ExecutorService和线程池。 - Hovercraft Full Of Eels
1
我在我的应用程序中遇到了类似的问题,通过IDE运行也是我的问题所在。 - Joel Christophel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接