Метод done SwingWorker выполняется даже до завершения doInBackground случайным образом.

У меня есть фрагмент кода JFrame, который останавливает SwingWorker при его закрытии:

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;

/**
 *
 * @author yccheok
 */
public class JavaApplication11 extends JFrame {

    public JavaApplication11() {
        this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        final Task task = new Task();
        task.execute();
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
                if (task != null) {
                    task.cancel(true);
                }
            }           
        }); 
    }

    public class Task extends SwingWorker<Void, Void> {

        @Override
        protected Void doInBackground() {
            for (int i = 0; i < 1000; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    System.out.println("interrupted in doInBackground");
                    break;
                }
                System.out.println("-> " + i);
            }
            return null;
        }

        @Override
        public void done() {
            System.out.println("DONE!!!");
        }        
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new JavaApplication11().setVisible(true);
    }
}

Однако случайным образом я понимаю, что когда я закрываю JFrame, метод done SwingWorker выполняется до завершения doInBackground. (Вам нужно выполнить вышеуказанный JFrame несколько раз, чтобы создать проблему)

-> 0
-> 1
-> 2
-> 3
-> 4
DONE!!!
interrupted in doInBackground

Могу я узнать, почему это так?


person Cheok Yan Cheng    schedule 13.09.2013    source источник
comment
Вероятно, это демонстрация состояния гонки с stdout   -  person MadProgrammer    schedule 13.09.2013
comment
Если MadProgrammer прав, включение метки времени в ваши вызовы sysout должно показать это... Одной из стратегий отслеживания этого будет включение исходного кода Swingworker в вашу IDE и установка точки останова на выполненном и последнем шаге doInBackgroun. .. просто мысль...   -  person Kevin Day    schedule 13.09.2013
comment
Разве не потому, что done вызывается в EDT, а doInBackground запускается в отдельном потоке, так что они точно не должны идти один за другим? И отменить автоматически сделанные звонки. Кроме того, просто добавьте еще один сон в блоке catch перед печатью, и вы будете видеть его каждый раз.   -  person sgbj    schedule 13.09.2013
comment
ЕСЛИ я понимаю, что происходит. Future, поддерживающий SwingWorker, отменяется, а метод done вызывается в контексте того же Thread. Это означает, что done может выполняться до того, как Thread, в котором выполняется метод doInBackground, будет запланировано для запуска и обнаружения прерывания...   -  person MadProgrammer    schedule 13.09.2013
comment
стандартная многопоточность, код (Thread.sleep невозможен для ....), вызываемый по умолчанию, выполняется, также необходимо уведомлять и останавливать этот код   -  person mKorbel    schedule 13.09.2013
comment
bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514   -  person Howard    schedule 13.09.2013
comment
Определенно состояние гонки потоков, потому что я получил и interrupted in doInBackground, и DONE!!!, и наоборот, как и вы.   -  person ryvantage    schedule 13.09.2013


Ответы (1)


Из комментария Говарда http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6826514 показывает, что это может быть ошибка.

Я тоже столкнулся с этим. Я обычно помещаю очистку внутрь doInBackground, если она зависит от порядка, и использую только done для обработки исключений.

@Override
protected Void doInBackground() {
    try {
        // ...
    } finally {
        // some cleanup inside 'doInBackground'
        if (isCancelled()) {
            // ...
        } else {
            // ...
        }
    }
    return (Void) null;
}
@Override
protected void done() {
    try {
        get();
    } catch (CancellationException x) {
        // ...
    } catch (InterruptedException x) {
        // ...
    } catch (ExecutionException x) {
        // ...
    }
}

(Не забудьте использовать invokeLater, если вам нужно обновить графический интерфейс с doInBackground.)

В моем случае у меня было что-то вроде этого:

  • doInBackground выполняя процедуру "открытия файла", периодически создавая компоненты Swing и добавляя их в графический интерфейс.
  • При отмене (через диалоговое окно индикатора выполнения с кнопкой Cancel) done удалит все компоненты, созданные во время doInBackground.

Иногда эти действия пересекались, и doInBackground продолжал создавать компоненты после того, как done выполнял очистку. Для пользователя это выглядело бы так, будто нажатие Cancel просто иногда не срабатывало, за исключением того, что отладка показывала, что вызывается done. Другого объяснения, кроме такого поведения SwingWorker, не было.

person Radiodef    schedule 17.10.2013