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

DiscardPolicy may block invokeAll forever

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      OS version: Mac OS Montery 12.3.1
      Java version: OpenJDK 64-Bit Server 25.322-b1

      A DESCRIPTION OF THE PROBLEM :
      DiscardPolicy just uses a no-op implementation to discard the submitted tasks, which causes rejected task remaining state NEW, which will block any get/invokeAll operation without time-bound parameters.

      as far as I search, this is an issue similar with https://bugs.openjdk.java.net/browse/JDK-8160037.

      According Doug's and Martin's comment, programmer can cancel the future task to avoid forever blocking, but invokeAll blocks forever so no one has a chance to cancel a task.

      Maybe DiscardPolicy and invokeAll are both implemented according to the spec, but they just don't work well together. Can someone change this mechanism so user can cancel the discarded task or let programmer get information from the API document so they just don't use 2 of them at the same time.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. use DiscardPolicy to initiate a thread pool executor.
      2. submit a lot of jobs via invokeAll API.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      invokeAll returns all results as expected.
      ACTUAL -
      invokeAll blocks forever.

      ---------- BEGIN SOURCE ----------
      public static void main(String[] args) {
              AtomicInteger counter = new AtomicInteger(0);
              // a very small thread pool which is easy to fulfilled
              ExecutorService testPool = new ThreadPoolExecutor(
                      1,
                      1,
                      1,
                      TimeUnit.SECONDS,
                      new ArrayBlockingQueue<>(1),
                      r -> {
                          Thread thread = new Thread(r);
                          thread.setName("test-thread" + counter.getAndIncrement());
                          return thread;
                      },
                      new ThreadPoolExecutor.DiscardPolicy()
              );

                      // gengerate several jobs here
              final List<Callable<Integer>> tasks = IntStream.range(1, 10).mapToObj((i) -> {
                  return new Callable<Integer>() {
                      /**
                       * Computes a result, or throws an exception if unable to do so.
                       *
                       * @return computed result
                       * @throws Exception if unable to compute a result
                       */
                      @Override
                      public Integer call() throws Exception {
                          // sleep to simulate long-run job
                          Thread.sleep(1000L);
                          return i;
                      }
                  };
              }).collect(Collectors.toList());
              try {
                  testPool.invokeAll(tasks);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              // you will never see this
              log.info("this executor can run through all tasks");
              testPool.shutdownNow();
              // you will never see this
              log.info("good bye");
          }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      use DiscardOldestPolicy instead.

      FREQUENCY : always


            dl Doug Lea
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: