JDK-7 SwingWorker тупиков? - PullRequest
       13

JDK-7 SwingWorker тупиков?

4 голосов
/ 27 августа 2009

У меня есть небольшое приложение для обработки изображений, которое делает несколько вещей одновременно, используя SwingWorker. Однако, если я запускаю следующий код (упрощенный отрывок), он просто зависает на JDK 7 b70 (windows), но работает в 6u16. Он запускает нового работника внутри другого работника и ожидает его результата (реальное приложение запускает несколько подчиненных и ждет всего этого). Использовал ли я здесь несколько неправильных шаблонов (так как в основном в пул свингеров, в которых, как мне кажется, есть предел 10), работает 3-5 человек?

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 ]

6 голосов
/ 04 мая 2010

Поскольку никто еще не запустил ссылку, похоже, это действительно известная ошибка:

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

Удивительно, но за то, что должно быть ошибкой showtopper для большинства нетривиальных приложений, менее 100 голосов.

1 голос
/ 28 августа 2009

Ваши SwingWorkers выполняются в вашей ветке SwingWorker. Поэтому, когда вы видите

Кажется, он зависает на sw2.get (), и в jdk7 есть только один поток с именем Swingworker. На jdk6 вижу сразу 3-5. - кд304

Это связано с тем, что класс SwingWorker является не потоком, а задачей, выполняемой в потоке, и конфигурация по умолчанию для ExecutorService для SwingWorker в Java 6 настроена иначе, чем в 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, и эта первая задача ожидает завершения второй задачи, которая не может быть запущена, поскольку поток, в котором будет выполняться вторая задача, ожидает вторую задание завершить, прежде чем оно вернется. Заставить нить зависимого работника зависеть от выполнения другого - верный путь к тупику. Возможно, вы захотите использовать ExecutorService для планирования событий, запускаемых в потоке SwingWorker, и не делать одно запланированное событие зависимым от завершения другого запланированного события.

Java 7 SwingWorker

0 голосов
/ 12 февраля 2010

До обновления 18 JDK вы можете запустить:

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).

Полагаю, замена вложенных SwingWorkers на executorService java.util.concurrent. Будущие вызовы - хороший обходной путь.

0 голосов
/ 27 августа 2009

Глядя на исходный код SwingWorker, похоже, что ExecutorService используется в качестве пула рабочих потоков. Вполне возможно, что тип используемого ExecutorService изменился между Java 6 и Java 7. Похоже, ваш код заблокируется, если ExecutorService управляет только 1 потоком одновременно (как вы, кажется, заметили).

Это потому, что ваш вызов sw2.get () заблокирует текущий поток, который является тем же потоком, который будет пытаться использовать sw2. sw2 никогда не сможет выполнить, потому что блокируется первый рабочий.

Я думаю, что лучшее решение - это изменить свою логику, чтобы вы не называли цепочки работников Swing такими.

...