JDK-8356825 : SwingWorker deadlock when running on Event Dispatch Thread
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 21,24,25
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2025-05-12
  • Updated: 2025-05-16
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 25
25Unresolved
Related Reports
Causes :  
Description
A DESCRIPTION OF THE PROBLEM :
The fix in JDK-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 ----------


Comments
I am able to reproduce the issue: doInBackground return result done() get() ... java.lang.InterruptedException at java.base/java.util.concurrent.FutureTask.awaitDone(FutureTask.java:482) at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:192) at java.desktop/javax.swing.SwingWorker.get(SwingWorker.java:610) at TestGetInDoneOnEventDispatchThread$Task.done(TestGetInDoneOnEventDispatchThread.java:34) at java.desktop/javax.swing.SwingWorker$4.run(SwingWorker.java:747) at java.desktop/javax.swing.SwingWorker.doneEDT(SwingWorker.java:751) at java.desktop/javax.swing.SwingWorker$1.call(SwingWorker.java:305) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:328) at java.desktop/javax.swing.SwingWorker.run(SwingWorker.java:340) at TestGetInDoneOnEventDispatchThread.lambda$testRunSwingWorkerInEDTgetResultInDone$0(TestGetInDoneOnEventDispatchThread.java:59) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:323) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:723) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:702) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) org.opentest4j.AssertionFailedError: Expected :true Actual :false Need to update our documentation or update the implementation.
15-05-2025

Impact -> H (Regression) Likelihood -> L (Uncommon uses) Workaround -> M (Somewhere in-between the extremes) Priority -> P3
13-05-2025

The observations on Windows 11: JDK 17: Passed, no test failed. JDK 21ea+11: Passed. JDK 21ea+12: Failed, failed test observed. JDK 25ea+6: Failed.
13-05-2025