JDK-8081474 : SwingWorker calls 'done' before the 'doInBackground' is finished
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 8u45,8u60
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2015-05-15
  • Updated: 2025-05-13
  • Resolved: 2023-02-27
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 21
21 b12Fixed
Related Reports
CSR :  
Causes :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b25)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
According to documentation of SwingWorker for method 'done':

"Executed on the Event Dispatch Thread after the doInBackground method is finished."

When cancelling a worker that needs to perform some cleanup the 'done' method is called on EDT before the worker finishes cleaning up.

This behavior is not logical and not correct according to documentation.

In the steps to reproduce i put a code listing that can be used to reproduce.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
- start a swing worker
- cancel it
- expect swing worker to do some cleanup


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Working...
(...)
Working...
Got interrupted!
Cleaning up
Done cleaning
Done

ACTUAL -
Working...
(...)
Working...
Got interrupted!
Cleaning up
Done
Done cleaning

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.swing.SwingWorker;

public class Main
{
    public static void main(String[] args) throws InterruptedException
    {
        SwingWorker<String, String> worker = new SwingWorker<String, String>()
        {
            @Override
            protected String doInBackground() throws Exception
            {
                try
                {
                    while (!Thread.currentThread().isInterrupted())
                    {
                        System.out.println("Working...");
                        Thread.sleep(1000);
                        
                    }
                }
                catch (InterruptedException ex)
                {
                    System.out.println("Got interrupted!");
                }
                
                try
                {
                    System.out.println("Cleaning up");
                    Thread.sleep(10000);
                    System.out.println("Done cleaning");
                }
                catch (InterruptedException ex)
                {
                    System.out.println("Got interrupted second time!");
                }
                
                return null;
            }
            
            @Override
            protected void done()
            {
                System.out.println("Done");
            }
        };
        
        worker.execute();
        Thread.sleep(10000);
        
        worker.cancel(true);
        Thread.sleep(20000);
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Reimplement the 'FutureTask' class.


Comments
Yes it is in headless environment (~2 times every month, seen on Windows).
31-01-2024

[~mbaesken] Is it in headless environment? I don't think adjusting any timeouts will help here. I see a similar exception—"AWT blocker activation interrupted: java.lang.InterruptedException"—while running my test for JDK-8323670. This InterruptedException is printed from AWT internals. It looks as if AWT EventQueue Thread shuts down but then EventQueue is created again. It needs more investigation.
30-01-2024

Hi [~psadhukhan] , the added test javax/swing/SwingWorker/TestDoneBeforeDoInBackground.java fails ~ 2 times per month in our test infra (we mostly run fastdebug, failures are seen on Windows). We get in most of the failures an exception like this : AWT blocker activation interrupted: java.lang.InterruptedException at java.base/java.lang.Object.wait0(Native Method) at java.base/java.lang.Object.wait(Object.java:375) at java.base/java.lang.Object.wait(Object.java:348) at java.desktop/sun.awt.AWTAutoShutdown.activateBlockerThread(AWTAutoShutdown.java:349) at java.desktop/sun.awt.AWTAutoShutdown.setToolkitBusy(AWTAutoShutdown.java:258) at java.desktop/sun.awt.AWTAutoShutdown.notifyToolkitThreadBusy(AWTAutoShutdown.java:144) at java.desktop/sun.awt.windows.WToolkit.<init>(WToolkit.java:225) at java.desktop/sun.awt.PlatformGraphicsInfo.createToolkit(PlatformGraphicsInfo.java:38) at java.desktop/java.awt.Toolkit.getDefaultToolkit(Toolkit.java:595) at java.desktop/java.awt.Toolkit.getEventQueue(Toolkit.java:1489) at java.desktop/java.awt.EventQueue.isDispatchThread(EventQueue.java:1089) at java.desktop/javax.swing.SwingUtilities.isEventDispatchThread(SwingUtilities.java:1493) at java.desktop/javax.swing.SwingWorker$SwingWorkerPropertyChangeSupport.firePropertyChange(SwingWorker.java:869) at java.desktop/java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:268) at java.desktop/javax.swing.SwingWorker.firePropertyChange(SwingWorker.java:688) at java.desktop/javax.swing.SwingWorker.setState(SwingWorker.java:739) at java.desktop/javax.swing.SwingWorker$1.call(SwingWorker.java:303) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) at java.desktop/javax.swing.SwingWorker.run(SwingWorker.java:342) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.lang.Thread.run(Thread.java:1575) java.lang.RuntimeException: done didn't complete in time at TestDoneBeforeDoInBackground.main(TestDoneBeforeDoInBackground.java:135) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at com.sun.javatest.regtest.agent.MainWrapper$MainTask.run(MainWrapper.java:138) at java.base/java.lang.Thread.run(Thread.java:1575) should we maybe adjust the values here to make the test more stable? if (!doneLatch.await(CLEANUP_TIME + 1000L, TimeUnit.MILLISECONDS)) { throw new RuntimeException("done didn't complete in time"); }
30-01-2024

Changeset: dbb5581e Author: Prasanta Sadhukhan <psadhukhan@openjdk.org> Date: 2023-02-27 09:19:57 +0000 URL: https://git.openjdk.org/jdk/commit/dbb5581eba5d765bca95585ba91f9b0eee9d1f57
27-02-2023

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/11940 Date: 2023-01-11 11:01:18 +0000
11-01-2023

SwingWorker uses the same convention as the FutureTask : the interrupted task is treated as done. Probably that need to be pointed in the documentation. And to cancel the running task it should be canceleable i.e. be responsive to interruption. I'm not sure that SwingWorker should track stages of the background process execution because that would require more complex API. Of cause Worker.cancel() cannot be blocking operation because it is usually run on EDT. If cancel() triggers long-running task there are several ways: use SwingWorker again to wait for cleaning in the background or use the SecondaryLoop.
02-06-2015

The problem is reproducible on 8u60 and 9-b66
29-05-2015