2009-08-27 2 views
4

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

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

} 
+0

Вы пытались получить свалку? –

+0

Кажется, он зависает на sw2.get(), и в jdk7 есть только один swingworker-named thread. На jdk6 я вижу 3-5 одновременно. – akarnokd

ответ

6

Как никто не выпалил ссылку все же, кажется, что это на самом деле известная ошибка:

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

Удивительно, но менее 100 голосов для того, что должно быть остановит всю работу ошибка для большинства нетривиальным Приложения.

+0

Да, и пример программы выглядит ужасно много, как у меня, не так ли? – akarnokd

0

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

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

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

+0

Хм, это не звучит совместимо с изменением - если у меня есть несколько исполнителей swingworkers, они всегда будут работать последовательно на JDK 7 (независимо от многоядерного процессора)? Наверное, я должен изменить внешний swingworker в обычный поток, например. – akarnokd

1

Ваши SwingWorkers выполнены в вашей теме SwingWorker. Итак, когда вы видите

Кажется, что он зависает на sw2.get(), и в jdk7 есть только один swingworker-named thread. На jdk6 я вижу 3-5 одновременно. - kd304

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

Java 7 SwingWorker

+0

Справедливое объяснение, но почему поведение изменилось? Я бы ожидал увидеть, что в JDK 7 начали работать 3 swingworker-threads? Тогда оригинальное многопоточное исполнение swignworker было ошибкой? – akarnokd

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

Я предполагаю, что замена вложенных swingWorkers с помощью executorService java.util.concurrent.Future вызывает хороший обходной путь.

+2

Свингеры не обязательно должны быть выполнены на EDT. На самом деле SwingWorker Javadoc явно упоминает «текущий поток», из которого порождается SwingWorker, и ничего не говорит о том, что это должен быть поток Dispatch. – Trejkaz