Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8356825

SwingWorker deadlock when running on Event Dispatch Thread

XMLWordPrintable

    • b12
    • 21
    • generic
    • generic

      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 ----------

            psadhukhan Prasanta Sadhukhan
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: