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

SwingWorker.isDone() returns false after task completed

XMLWordPrintable

      FULL PRODUCT VERSION :
      java version "1.6.0_02"
      Java(TM) SE Runtime Environment (build 1.6.0_02-b05)
      Java HotSpot(TM) Client VM (build 1.6.0_02-b05, mixed mode, sharing)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows 2000 [Version 5.00.2195]

      A DESCRIPTION OF THE PROBLEM :
      According to the JDK documentation, SwingWorker.isDone() returns true "if this task completed".

      What exactly does "task completed" mean? Since a call to isDone() within an implementation of done() always returns true, I can see no possibility other than the return of the doInBackground method as the point in time when the task completes. The problem is that isDone() might return false even after the doInBackground method has returned.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the attached code. Depending on the performance of your system, you might have to play around with its time variables to reproduce the supposed bug.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The code should produce an endless sequence of output text blocks like

      29193342 mySwingWorker: doInBackground returns
      29193342 timerActionListener: mySwingWorker is done

      or

      29459700 timerActionListener: mySwingWorker is NOT done - stop timer
      29459700 mySwingWorker: start timer
      29459700 mySwingWorker: doInBackground returns
      29459700 timerActionListener: mySwingWorker is done
      ACTUAL -
      The program stops once the supposed bug hits with an output text block like

      3373112 timerActionListener: mySwingWorker is NOT done - stop timer
      3373112 mySwingWorker: start timer
      3373112 mySwingWorker: doInBackground returns
      3373112 timerActionListener: mySwingWorker is NOT done - stop timer

      or

      12694833 mySwingWorker: doInBackground returns
      12694833 timerActionListener: mySwingWorker is NOT done - stop timer

      Since synchronizing on the lockObject establishes a happens-before relationship between the return of the doInBackground method in MySwingWorker and the calling of the isDone method in TimerActionListener,
      the output shows that isDone() returns false after the task completes.

      REPRODUCIBILITY :
      This bug can be reproduced often.

      ---------- BEGIN SOURCE ----------
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import javax.swing.Timer;
      import javax.swing.SwingWorker;

      class SwingWorkerBugDemo {

          // Play around with these values to vary likelihood of bug encounter.
          int timerDelayMillis = 20;
          int sleepTimeMillis = 10;

          Timer timer;
          boolean doStartTimer;
          MySwingWorker mySwingWorker;
          Object lockObject = new Object();

          SwingWorkerBugDemo() {
              timer = new Timer(timerDelayMillis, new TimerActionListener());
              timer.setInitialDelay(0);
              mySwingWorker = new MySwingWorker();
              mySwingWorker.execute();
              timer.start();
          }

          public static void main(String[] args) {
              new SwingWorkerBugDemo();
          }

          class TimerActionListener implements ActionListener {
              public void actionPerformed(ActionEvent e) {
                  synchronized (lockObject) {
                      if (mySwingWorker.isDone()) {
                          System.out.println(mySwingWorker.hashCode() + " timerActionListener: mySwingWorker is done\n");
                          mySwingWorker = new MySwingWorker();
                          mySwingWorker.execute();
                      } else {
                          System.out.println(mySwingWorker.hashCode() + " timerActionListener: mySwingWorker is NOT done - stop timer");
                          timer.stop();
                          doStartTimer = true;
                      }
                  }
              }
          }

          class MySwingWorker extends SwingWorker<Object, Object> {
              public Object doInBackground() {
                  try {
                      Thread.sleep(sleepTimeMillis);
                  } catch (InterruptedException ex) {
                  }
                  synchronized (lockObject) {
                      if (doStartTimer) {
                          System.out.println(this.hashCode() + " mySwingWorker: start timer");
                          timer.start();
                          doStartTimer = false;
                      }
                      System.out.println(this.hashCode() + " mySwingWorker: doInBackground returns");
                      return null;
                  }
              }
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Don't use isDone() to find out if task completed.

            peterz Peter Zhelezniakov
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: