Когда поток отменяется через
myWorkerThread.cancel(true/false);
Метод done (как ни удивительно) вызывается самим методом cancel.
То, что вы можете ожидать, но на самом деле НЕ:
- вы звоните отменить (с MayInterrupt или нет)
- отменить настройку потока отмена
- выход из doInBackground
- готово называется *
(* готово поставлено в очередь к EDT, это означает, что, если EDT занят, это происходит ПОСЛЕ того, как EDT завершил свою работу)
Что на самом деле происходит:
- вы звоните отменить (с MayInterrupt или нет)
- отменить настройку потока отмена
- Готово вызывается как часть кода отмены *
- doInBackground завершит работу, когда завершит свой цикл
(* Готово не ставится в очередь к EDT, но вызывается на вызов отмены, и поэтому оно оказывает очень непосредственное влияние на EDT, который часто является GUI)
Я приведу простой пример, который доказывает это.
Скопируйте, вставьте и запустите.
1. Я генерирую исключение во время выполнения внутри готово. Поток стека показывает, что done вызывается методом cancel.
2. Примерно через 4 секунды после отмены вы получите приветствие от doInBackground, которое еще раз доказывает, что done вызывается до выхода из потока.
import java.awt.EventQueue;
import javax.swing.SwingWorker;
public class SwingWorker05 {
public static void main(String [] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
W w = new W();
w.execute();
Thread.sleep(1000);
try{w.cancel(false);}catch (RuntimeException rte) {
rte.printStackTrace();
}
Thread.sleep(6000);
} catch (InterruptedException ignored_in_testing) {}
}
});
}
public static class W extends SwingWorker <Void, Void> {
@Override
protected Void doInBackground() throws Exception {
while (!isCancelled()) {
Thread.sleep(5000);
}
System.out.println("I'm still alive");
return null;
}
@Override
protected void done() {throw new RuntimeException("I want to produce a stack trace!");}
}
}