4

我有一个小型图像处理应用程序,它使用 SwingWorker 一次执行多项操作。但是,如果我运行以下代码(过于简化的摘录),它只会挂在 JDK 7 b70(Windows)上,但可以在 6u16 中运行。它在另一个工作人员中启动一个新工作人员并等待其结果(真正的应用程序运行多个子工作人员并一直等待)。我在这里使用了一些错误的模式吗(因为在 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

4 回答 4

6

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

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

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

于 2010-05-04T01:12:03.943 回答
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

于 2009-08-27T20:15:59.410 回答
0

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

这是因为您的“sw2.get()”调用将阻塞当前线程,这与 sw2 将尝试使用的线程相同。sw2 永远无法执行,因为第一个工作人员正在阻塞。

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

于 2009-08-27T16:56:48.610 回答
-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 是一个很好的解决方法。

于 2010-02-12T11:27:08.090 回答