When a thread is cancelled via
myWorkerThread.cancel(true/false);
the done method is (quite surprisingly) called by the cancel method itself.
What you may expect to happen, but actually DOESN'T:
- you call cancel (either with mayInterrupt or not)
- cancel set up the thread cancellation
- the doInBackground exits
- the done is called*
(* the done is enqueued to the EDT, that means, if EDT is busy it happens AFTER the EDT has finished what it is doing)
What actually DOES happen:
- you call cancel (either with mayInterrupt or not)
- cancel set up the thread cancellation
- the done is called as part of cancel code*
- the doInBackground will exit when it will have finished its loop
(*the done isn't enqueued to the EDT, but called into the cancel call and so it has a very immediate effect on EDT, that often is the GUI)
I provide a simple example that proves this.
Copy, paste and run.
1. I generate a runtime exception inside done. The stack thread shows that done is called by cancel.
2. About after 4 seconds after cancelation, you'll recive a greeting from the doInBackground, that fhurterly proves that done is called before the thread exiting.
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!");}
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…