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

SwingWorker intermediate results are processed out of order

XMLWordPrintable

      FULL PRODUCT VERSION :
      java version "1.6.0_07"
      Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
      Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)
      ---
      java version "1.6.0_10-rc"
      Java(TM) SE Runtime Environment (build 1.6.0_10-rc-b28)
      Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)
      ---
      java version "1.6.0_07"
      Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
      Java HotSpot(TM) 64-Bit Server VM (build 10.0-b23, mixed mode)
      ---
      java version "1.6.0_10-rc"
      Java(TM) SE Runtime Environment (build 1.6.0_10-rc-b28)
      Java HotSpot(TM) 64-Bit Server VM (build 11.0-b15, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Linux hostname 2.6.8-4-686 #1 Wed Feb 20 03:50:44 UTC 2008 i686 GNU/Linux
      Linux hostname 2.6.21-1.3194.fc7 #1 SMP Wed May 23 22:35:01 EDT 2007 i686 i686 i386 GNU/Linux
      Linux hostname 2.6.5-suse-sfs #1 SMP Mon Oct 9 10:28:27 BST 2006 x86_64 GNU/Linux

      A DESCRIPTION OF THE PROBLEM :
      Intermediate results published during the execution of SwingWorker's doInBackground method are delivered by the process method out of order.

      In fact, the first result object passed to the publish method is delivered by the process method after *all* of the other result objects, and *after* the done method has been invoked.

      This bug has been reported previously as Bug ID 6493680 which was allegedly fixed in releases 7(b07) and 6u1(b01). However, it still manifests itself in the current (August 18, 2008) latest stable release 1.6.0_07-b06 and the latest beta release 1.6.0_10-rc-b28 of Java 6.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the attached demo program, which executes a "long running" task using a sub-class of SwingWorker which reports the progress via a dialog box and by printing messages to System.err

      Push the "Run task" button to begin the task.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The intermediate results are published in the order START, WORKING #0, WORKING #1, ..., WORKING #9, DONE.

      I expect to see these results passed to the Event Despatch Thread via the process method in the *same* order.
      ACTUAL -
      The results are actually reported by the process method in the order WORKING #0, WORKING #1, ..., WORKING #9, DONE, done method is invoked, START

      i.e. the first intermediate result is reported *last*, and *after* the done method is invoked.

      This behaviour is observed if the task is allowed to run to completion, and also when the task is cancelled.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import javax.swing.JFrame;
      import javax.swing.JPanel;
      import javax.swing.JLabel;
      import javax.swing.JButton;
      import javax.swing.JDialog;
      import javax.swing.SwingUtilities;
      import javax.swing.SwingWorker;

      import java.awt.*;
      import java.awt.event.*;
      import java.util.List;
      import java.util.Vector;

      public class Worker extends SwingWorker<List, ProgressMessage> {
      private WorkerFrame frame;
      private int maxvalue;
      private WorkerDialog dialog;
      private long taskStartTime;

      public Worker(WorkerFrame frame, int maxvalue) {
      this.frame = frame;
      this.maxvalue = maxvalue;
      }

      protected List doInBackground() throws Exception {
      taskStartTime = System.currentTimeMillis();

      System.err.println("----------------------------------------------------");
      System.err.println("Entered doInBackground method");

      int value = 0;

      publish(new ProgressMessage(ProgressMessage.START, value, taskStartTime));

      while (value < maxvalue) {
      Thread.sleep(1000L);
      publish(new ProgressMessage(ProgressMessage.WORKING, value++, taskStartTime));
      }

      publish(new ProgressMessage(ProgressMessage.DONE, value, taskStartTime));

      Vector v = new Vector();

      System.err.println("Exited doInBackground method");

      return v;
      }

      protected void done() {
      System.err.println("Entered done method");

      if (isCancelled())
      System.err.println("The task was cancelled");

      if (dialog != null && dialog.isVisible()) {
      dialog.setVisible(false);
      dialog.dispose();
      }

      frame.enableButton();

      System.err.println("Exited done method");
      }

      protected void process(List<ProgressMessage> chunks) {
      long dt = System.currentTimeMillis() - taskStartTime;

      if (dialog == null && !isDone()) {
      System.err.println("Creating a new WorkerDialog at time " + dt);
      dialog = new WorkerDialog(frame);
      dialog.setVisible(true);
      }

      int nChunks = chunks == null ? 0 : chunks.size();

      System.err.println("process received " + nChunks + " ProgressMessage" +
      (nChunks == 1 ? "" : "s") + " at time " + dt);

      for (ProgressMessage message : chunks) {
      System.err.println(message);

      if (dialog != null) {
      String status = message.getStatusAsString();
      int value = message.getValue();
      dialog.setStatus(status);
      dialog.setValue(value);
      }
      }
      }

      class WorkerDialog extends JDialog {
      private JLabel lblStatus = new JLabel("NO STATUS YET");
      private JLabel lblValue = new JLabel("NO VALUE YET");

      public WorkerDialog(JFrame frame) {
      super(frame, "Progress", true);

      JPanel mainpanel = new JPanel(new BorderLayout());

      JPanel buttonpanel = new JPanel(new FlowLayout(FlowLayout.CENTER));

      JButton btnCancel = new JButton("Cancel");
      btnCancel.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
      cancelTask();
      }
      });

      buttonpanel.add(btnCancel);

      mainpanel.add(buttonpanel, BorderLayout.SOUTH);

      JPanel panel = new JPanel(new GridLayout(2, 2));

      panel.add(new JLabel("Status:"));
      panel.add(lblStatus);

      panel.add(new JLabel("Value:"));
      panel.add(lblValue);

      mainpanel.add(panel, BorderLayout.CENTER);

      setContentPane(mainpanel);

      setResizable(false);

      setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);

      pack();
      }

      public void setStatus(String status) {
      lblStatus.setText(status);
      }

      public void setValue(int value) {
      lblValue.setText("" + value);
      }

      private void cancelTask() {
      System.err.println("Cancel button pressed");
      Worker.this.cancel(true);
      }
      }

      public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
      public void run() {
      WorkerFrame frame = new WorkerFrame();
      frame.setVisible(true);
      }
      });
      }
      }

      class WorkerFrame extends JFrame {
      final JButton button = new JButton("Run task");

      public WorkerFrame() {
      super("SwingWorker demo");

      Container cp = getContentPane();

      cp.setLayout(new GridLayout(2, 1));

      cp.add(new JLabel("Press the button to run a new task"));

      button.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
      button.setEnabled(false);
      Worker worker = new Worker(WorkerFrame.this, 10);
      worker.execute();
      }
      });

      cp.add(button);

      pack();

      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      }

      public void enableButton() {
      button.setEnabled(true);
      }
      }

      class ProgressMessage {
      public static final int START = 0;
      public static final String START_STRING = "START";

      public static final int WORKING = 1;
      public static final String WORKING_STRING = "WORKING";

      public static final int DONE = 2;
      public static final String DONE_STRING = "DONE";

      public static final String UNKNOWN_STRING = "UNKNOWN";

      private int status;
      private int value;
      private long creationTime;

      public ProgressMessage(int status, int value, long taskStartTime) {
      this.status = status;
      this.value = value;
      creationTime = System.currentTimeMillis() - taskStartTime;
      }

      public int getStatus() {
      return status;
      }

      public String getStatusAsString() {
      switch (status) {
      case START:
      return START_STRING;

      case WORKING:
      return WORKING_STRING;

      case DONE:
      return DONE_STRING;

      default:
      return UNKNOWN_STRING;
      }
      }

      public int getValue() {
      return value;
      }

      public String toString() {
      return "ProgressMessage[status=" + getStatusAsString() + ", value="
      + value + ", created=" + creationTime + "]";
      }
      }

      ---------- END SOURCE ----------

      Release Regression From : 6
      The above release value was the last known release where this
      bug was not reproducible. Since then there has been a regression.

            idk Igor Kushnirskiy (Inactive)
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: