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

DelayScheduler.replace method may break the 4-ary heap in certain scenarios

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • None
    • 25.0.1
    • core-libs

      A DESCRIPTION OF THE PROBLEM :
      When performing sift-down operation, the moved "t' may not be a child of the target place, causing the min-heap structure being broken.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Execute the test code.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Tasks are executed in the ascending order of their respective delay, outputting the following content:

      Delay 200
      Delay 310
      Delay 420
      Delay 430
      Delay 400
      Delay 500
      Delay 700
      Delay 800
      Delay 900
      ACTUAL -
      The output is as following. Note the 400-delayed task is executed after the 420 and 430 ones.

      Delay 200
      Delay 310
      Delay 400
      Delay 420
      Delay 430
      Delay 500
      Delay 700
      Delay 800
      Delay 900

      ---------- BEGIN SOURCE ----------
      import java.util.concurrent.CountDownLatch;
      import java.util.concurrent.ForkJoinPool;
      import java.util.concurrent.ScheduledFuture;
      import java.util.concurrent.TimeUnit;

      public class Application {

          private static final long[] DELAYS = new long[] {400, 900, 800, 700, 600, 430, 420, 310, 500, 200};
          private static final int DELAY_OFFSET = 5000;
          private static final CountDownLatch LATCH = new CountDownLatch(DELAYS.length);

          public static void main(String[] args) throws Exception {

              ScheduledFuture<?>[] tasks = new ScheduledFuture[DELAYS.length];
              ForkJoinPool pool = ForkJoinPool.commonPool();
              for (int i = 0; i < DELAYS.length; ++i) {
                  TestRunnable runnable = new TestRunnable(DELAYS[i]);
                  tasks[i] = pool.schedule(runnable, runnable.delay + DELAY_OFFSET, TimeUnit.MILLISECONDS);
              }
              Thread.sleep(50);
              tasks[4].cancel(true);
              LATCH.countDown();
              LATCH.await();
          }

          private static class TestRunnable implements Runnable {

              private final long delay;

              public TestRunnable(long delay) {
                  this.delay = delay;
              }

              @Override
              public void run() {
                  synchronized (TestRunnable.class) {
                      System.out.println("Delay " + delay);
                  }
                  LATCH.countDown();
              }

              @Override
              public String toString() {
                  return "toString called for delay " + delay;
              }
          }
      }

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

            vklang Viktor Klang
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: