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

ConcurrentHashMap.entrySet().removeIf() would run into infinite loop

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      Java HotSpot(TM) 64-Bit Server VM (21.0.1+12-LTS-29) for bsd-amd64 JRE (21.0.1+12-LTS-29), built on 2023-10-05T13:27:09Z by "mach5one" with clang Apple LLVM 12.0.0 (clang-1200.0.32.29)

      A DESCRIPTION OF THE PROBLEM :
      ConcurrentHashMap.removeIf() would run into infinite loop if add and remove operation happened at same time

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      reproduce code:
      class Scratch {
          public static void main(String[] args) throws InterruptedException {
              var map = new ConcurrentHashMap<Integer, Optional<Integer>>();
              try (ExecutorService executor = Executors.newWorkStealingPool()) {
                  Future<?> addTask =
                          executor.submit(() -> IntStream.range(0, 1_000_000_000)
                                  .forEach(i -> map.put(i, i % 2 == 0 ? Optional.of(i) : Optional.empty())));
                  Future<Boolean> removeTask =
                          executor.submit(() -> map.entrySet().removeIf(e -> e.getValue().isEmpty()));
                  removeTask.wait();
              }
              System.out.println("Program Finished");
          }

      }

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      the expected result is the program should complete two future tasks and print out "Program Finished"
      ACTUAL -
      the program stuck in the loop and never exit.

      ---------- BEGIN SOURCE ----------
      class Scratch {
          public static void main(String[] args) throws InterruptedException {
              var map = new ConcurrentHashMap<Integer, Optional<Integer>>();
              try (ExecutorService executor = Executors.newWorkStealingPool()) {
                  Future<?> addTask =
                          executor.submit(() -> IntStream.range(0, 1_000_000_000)
                                  .forEach(i -> map.put(i, i % 2 == 0 ? Optional.of(i) : Optional.empty())));
                  Future<Boolean> removeTask =
                          executor.submit(() -> map.entrySet().removeIf(e -> e.getValue().isEmpty()));
                  removeTask.wait();
              }
              System.out.println("Program Finished");
          }

      }
      ---------- END SOURCE ----------

            smarks Stuart Marks
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: