-
Bug
-
Resolution: Unresolved
-
P3
-
21, 24, 25
-
b12
-
generic
-
generic
A DESCRIPTION OF THE PROBLEM :
The fix inJDK-8081474 broke working legacy code.
Now it is not possible anymore to subclass from SwingWorker and invoke get() in the done() override, when the worker is run on in the Event Dispatch Thread.
The documentation of done() still specifies, that "you can query status inside the implementation of this method to determine the result of this task".
And the javax.swing.SwingWorker.doneEDT() method still has an explicit case for what to do, if it is invoked on the Event Dispatch Thread.
However, doing so now runs into a deadlock, because the future's get() method is invoked while it is still executing on the same thread.
REGRESSION : Last worked in version 20
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Subclass from SwingWorker.
Override done().
Call get() in done() override.
Execute run() on the Event Dispatch Thread.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Execution of done() returns and worker task terminates.
ACTUAL -
deadlock
---------- BEGIN SOURCE ----------
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import org.junit.jupiter.api.Test;
public class TestGetInDoneOnEventDispatchThread {
private CountDownLatch latch = new CountDownLatch(1);
private class Task
extends SwingWorker<String, Void> {
@Override
protected String doInBackground()
throws Exception {
System.out.println("doInBackground");
String result = "result";
System.out.println(" return " + result);
return result;
}
@Override
protected void done() {
try {
System.out.println("done()");
System.out.println(" get() ...");
String result = get();
System.out.println(" retrieved " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
}
}
private Thread findAwtEventQueue() {
for (Thread t : Thread.getAllStackTraces().keySet()) {
if ("AWT-EventQueue-0".equals(t.getName())) {
return t;
}
}
return null;
}
@Test
public void testRunSwingWorkerInEDTgetResultInDone()
throws InvocationTargetException, InterruptedException {
SwingUtilities.invokeLater(() -> {
Task task = new Task();
task.run();
});
try {
assertTrue(latch.await(3, TimeUnit.SECONDS));
} finally {
Thread awtEventQueue = findAwtEventQueue();
if (awtEventQueue != null) {
awtEventQueue.interrupt();
}
}
}
}
---------- END SOURCE ----------
The fix in
Now it is not possible anymore to subclass from SwingWorker and invoke get() in the done() override, when the worker is run on in the Event Dispatch Thread.
The documentation of done() still specifies, that "you can query status inside the implementation of this method to determine the result of this task".
And the javax.swing.SwingWorker.doneEDT() method still has an explicit case for what to do, if it is invoked on the Event Dispatch Thread.
However, doing so now runs into a deadlock, because the future's get() method is invoked while it is still executing on the same thread.
REGRESSION : Last worked in version 20
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Subclass from SwingWorker.
Override done().
Call get() in done() override.
Execute run() on the Event Dispatch Thread.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Execution of done() returns and worker task terminates.
ACTUAL -
deadlock
---------- BEGIN SOURCE ----------
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import org.junit.jupiter.api.Test;
public class TestGetInDoneOnEventDispatchThread {
private CountDownLatch latch = new CountDownLatch(1);
private class Task
extends SwingWorker<String, Void> {
@Override
protected String doInBackground()
throws Exception {
System.out.println("doInBackground");
String result = "result";
System.out.println(" return " + result);
return result;
}
@Override
protected void done() {
try {
System.out.println("done()");
System.out.println(" get() ...");
String result = get();
System.out.println(" retrieved " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
}
}
private Thread findAwtEventQueue() {
for (Thread t : Thread.getAllStackTraces().keySet()) {
if ("AWT-EventQueue-0".equals(t.getName())) {
return t;
}
}
return null;
}
@Test
public void testRunSwingWorkerInEDTgetResultInDone()
throws InvocationTargetException, InterruptedException {
SwingUtilities.invokeLater(() -> {
Task task = new Task();
task.run();
});
try {
assertTrue(latch.await(3, TimeUnit.SECONDS));
} finally {
Thread awtEventQueue = findAwtEventQueue();
if (awtEventQueue != null) {
awtEventQueue.interrupt();
}
}
}
}
---------- END SOURCE ----------
- caused by
-
JDK-8081474 SwingWorker calls 'done' before the 'doInBackground' is finished
-
- Resolved
-