JDK-7 SwingWorker 死锁?

发布于 2024-08-03 23:20:43 字数 1656 浏览 15 评论 0原文

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

}

I have a small image processing application which does multiple things at once using SwingWorker. However, if I run the following code (oversimplified excerpt), it just hangs on JDK 7 b70 (windows) but works in 6u16. It starts a new worker within another worker and waits for its result (the real app runs multiple sub-workers and waits for all this way). Did I use some wrong patterns here (as mostly there is 3-5 workers in the swingworker-pool, which has limit of 10 I think)?

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();
                       }
               });
       }

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一页 2024-08-10 23:20:43

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

https: //bugs.java.com/bugdatabase/view_bug?bug_id=6880336

令人惊讶的是,对于大多数重要应用程序来说,这个应该是一个令人瞩目的错误的投票数还不到 100 票。

As nobody has fired off the link yet, it seems this is actually a known bug:

https://bugs.java.com/bugdatabase/view_bug?bug_id=6880336

Surprisingly there are less than 100 votes for what should be a showstopper bug for most non-trivial applications.

箹锭⒈辈孓 2024-08-10 23:20:43

您的 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< /a> 安排要在 SwingWorker 线程上运行的事件,并且不要使一个计划事件依赖于另一计划事件的完成。

Java 7 SwingWorker

Your SwingWorkers are executed in your SwingWorker Thread. So when you see

It seems it hangs on sw2.get() and there is only one swingworker- named thread in jdk7. On jdk6, I see 3-5 at once. – kd304

This is because the SwingWorker class is not a thread, but a task to be run on a thread, and the default configuration for the ExecutorService for SwingWorker in Java 6 is configured different from the one in Java 7. IE your SwingWorkerExecutorService (which is defined inside the SwingWorker class) has a different value for the max number of Threads to allocate to the tasks.

//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)
}

You only have the one thread running the SwingWorker tasks, and that first task is waiting for the completion of the second task, which can't be run, because the Thread the second task would be run on is waiting for the second task to complete before it will return. Making on swingworker thread dependent on the execution of another is a sure path to deadlock. You may want to look at using an ExecutorService to schedule events to be run on the SwingWorker Thread, and don't make one scheduled event dependent on another scheduled event's completion.

Java 7 SwingWorker

維他命╮ 2024-08-10 23:20:43

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

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

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

Looking at the source code for SwingWorker, it looks like an ExecutorService is being used as a pool of worker threads. It's possible that the type of ExecutorService used has changed between Java 6 and Java 7. It looks like your code will deadlock if the ExecutorService only manages exactly 1 thread at a time (as you seem to have noticed).

This is because your 'sw2.get()' call will block the current thread, which is the same thread the sw2 will try to use. sw2 can never execute because the first worker is blocking.

I think the best solution is to change your logic so that you don't call chains of Swing workers like this.

随风而去 2024-08-10 23:20:43

在 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 是一个很好的解决方法。

Before JDK update 18 you could run:

public static void main(String[] args) {

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

}

This code doesn't work anymore, simply because SwingWorkers must be executed on EDT.

Therefore, you can't nest SwingWorkers (sw2 will never run in you sample code in newer JDKs).

I guess replacing nested swingWorkers with executorService java.util.concurrent.Future calls is a good workaround.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文