JDK-7 SwingWorker死锁?

时间:2009-08-27 16:42:51

标签: java swing swingworker java-7

我有一个小型图像处理应用程序,可以使用SwingWorker一次执行多项操作。但是,如果我运行以下代码(过度简化的摘录),它只挂在JDK 7 b70(Windows)上,但在6u16中工作。它在另一个worker中启动一个新的worker并等待其结果(真正的app运行多个子工作者并等待所有这些)。我是否在这里使用了一些错误的模式(因为在swingworker-pool中大多有3-5名工人,我认为其限制为10)?

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

public class Swing {
       static SwingWorker<String, Void> getWorker2() {
               return new SwingWorker<String, Void>() {
                       @Override
                       protected String doInBackground() throws Exception {
                               return "Hello World";
                       }
               };
       }
       static void runWorker() {
               SwingWorker<String, Void> worker 
                   = new SwingWorker<String, Void>() {
                       @Override
                       protected String doInBackground() throws Exception {
                               SwingWorker<String, Void> sw2 = getWorker2();
                               sw2.execute();
                               return sw2.get();
                       }
               };
               worker.execute();
               try {
                       System.out.println(worker.get());
               } catch (Exception e) {
                       e.printStackTrace();
               }
       }
       public static void main(String[] args) {
               SwingUtilities.invokeLater(new Runnable() {
                       @Override
                       public void run() {
                               runWorker();
                       }
               });
       }

}

4 个答案:

答案 0 :(得分:6)

由于没有人关闭链接,似乎这实际上是一个已知的错误:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6880336

令人惊讶的是,对于大多数非平凡的应用来说,应该是一个showstopper错误的票数不到100票。

答案 1 :(得分:1)

您的SwingWorkers在您的SwingWorker线程中执行。所以,当你看到

  

似乎它挂在了sw2.get()上,并且在jdk7中只有一个以swingworker命名的线程。在jdk6上,我立刻看到3-5。 - kd304

这是因为SwingWorker类不是一个线程,而是一个要在线程上运行的任务,并且Java 6中SwingWorker的ExecutorService的默认配置配置与Java 7中的不同.IE您的SwingWorkerExecutorService(在SwingWorker类中定义的)具有不同的值,用于分配给任务的最大线程数。

//From Java 6 SwingWorker

private static final int MAX_WORKER_THREADS = 10;

public final void execute() {
    getWorkersExecutorService().execute(this);
}

private static synchronized ExecutorService getWorkersExecutorService() {
...
private static synchronized ExecutorService getWorkersExecutorService() {
new ThreadPoolExecutor(0, MAX_WORKER_THREADS,
                                     1L, TimeUnit.SECONDS,
                                     new LinkedBlockingQueue<Runnable>(),
                                     threadFactory)
}

你只有一个线程运行SwingWorker任务,并且第一个任务正在等待第二个任务的完成,这个任务无法运行,因为运行第二个任务的线程正在等待第二个任务任务完成之前它将返回。依赖于另一个执行的swingworker线程是一个肯定的死锁路径。您可能希望使用ExecutorService来安排要在SwingWorker线程上运行的事件,并且不要使一个预定事件依赖于另一个预定事件的完成。

  

Java 7 SwingWorker

答案 2 :(得分:0)

查看SwingWorker的源代码,看起来ExecutorService被用作工作线程池。在Java 6和Java 7之间使用的ExecutorService类型可能已经发生了变化。如果ExecutorService一次只管理1个线程(您似乎已经注意到了),那么您的代码看起来就会死锁。

这是因为你的'sw2.get()'调用会阻塞当前线程,这与sw2尝试使用的线程相同。 sw2永远不会执行,因为第一个worker正在阻塞。

我认为最好的解决方案是改变你的逻辑,这样就不会像这样调用Swing工作者链。

答案 3 :(得分:-1)

在JDK更新18之前,您可以运行:

public static void main(String[] args) {

    new SwingWorker<Void, Void>() {
        @Override
        protected Void doInBackground() throws Exception {
            System.out.println("ok");
            return null;
        }
    }.execute();

}

此代码不再起作用,因为SwingWorkers必须在EDT上执行。

因此,您无法嵌套SwingWorkers(sw2永远不会在新JDK中的示例代码中运行)。

我想用executorService java.util.concurrent.Future调用替换嵌套的swingWorkers是一个很好的解决方法。