Вопрос

У меня есть небольшое приложение для обработки изображений, которое делает несколько вещей одновременно с помощью SwingWorker.Однако, если я запущу следующий код (упрощенный отрывок), он просто зависнет в JDK 7 b70 (Windows), но будет работать в 6u16.Он запускает нового работника внутри другого работника и ждет его результата (реальное приложение запускает несколько подчиненных рабочих процессов и ждет всего этого).Использовал ли я здесь какие-то неправильные шаблоны (поскольку в основном в пуле свинг-воркеров есть 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();
                       }
               });
       }

}
Это было полезно?

Решение

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

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

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

Другие советы

Ваши SwingWorker выполняются в вашем потоке 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, и эта первая задача ожидает завершения второй задачи, которую невозможно запустить, поскольку поток, в котором будет выполняться вторая задача, ожидает завершения второй задачи. прежде чем оно вернется.Создание зависимости потока Swingworker от выполнения другого — верный путь к тупику.Возможно, вы захотите использовать ИсполнительСервис планировать запуск событий в потоке SwingWorker и не ставить одно запланированное событие в зависимость от завершения другого запланированного события.

Java 7 Свингворкер

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

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

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

До обновления 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 является хорошим обходным решением.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top