I'm using a SwingWorker as a way to wrap non swing tasks/actions with a before and after methods always running in the Event Dispatch Thread (in other words: I invoke before then I invoke an abstract method in the doInBackground and then I invoke after in the done method). This started causing a lot of trouble lately since whatever happens in doInBackground has to be synchronized. I noticed that the problem goes away if I call run instead of execute, but from what I understand the run method works the same as in Thread, it just starts the execution in the exact same thread it has been called from instead of creating a new one, and as such the doInBackground executes on the EDT if I call run from the EDT. Is my thinking correct? How can I synchronize the doInBackground method with the thread calling execute on the worker?
I used the following code but it seems to be creating a thread lock:
private Object LOCK = new Object();
public final void method() {
someObject.before();
SwingWorker<Void, Void> worker1 = new SwingWorker<Void, Void>() {
protected Void doInBackground() throws Exception {
methodExt();
return null;
}
protected void done() {
someObject.after();
synchronized (LOCK) {
LOCK.notifyAll();
}
}
};
worker1.execute();
synchronized (LOCK) {
try {
LOCK.wait();
} catch (InterruptedException exception) {
exception.printStackTrace();
}
}
}
You should never block on the EDT. The whole point of SwingWorker
is that it allows you to trigger a task to run on a background thread and schedule additional code to run on the EDT after the background job is complete without blocking the EDT in the meantime. So if you want to run methodA()
on the EDT, then methodB()
in the background, then methodC()
back on the EDT after B has completed, the answer is to call methodC()
from the done()
method of the SwingWorker
.
Instead of trying to do
doSomething();
method(); // which blocks waiting for the BG task to complete
doSomethingElse();
you could modify method()
to
public final void method(final Runnable callback) {
someObject.before();
SwingWorker<Void, Void> worker1 = new SwingWorker<Void, Void>() {
protected Void doInBackground() throws Exception {
methodExt();
return null;
}
protected void done() {
someObject.after();
if(callback != null) callback.run();
}
};
worker1.execute();
}
and then call it as
doSomething();
method(new Runnable() {
public void run() {
doSomethingElse();
}
});
Now method
returns immediately and does not block the EDT, but doSomethingElse
still happens on the EDT after the background task is complete.