code: public <ReturnType> CompletableFuture<ReturnType> add(Collection<KeyType> keys, Supplier<CompletableFuture<? extends ReturnType>> toRun) {
          Preconditions.checkArgument(!keys.isEmpty(), "keys cannot be empty.");
          CompletableFuture<ReturnType> result = new CompletableFuture<>();
          ArrayList<CompletableFuture<?>> existingTasks = new ArrayList<>();
          synchronized (this.queue) {
              Exceptions.checkNotClosed(this.closed, this);
  
              // Collect all currently executing tasks for the given keys.
              for (KeyType key : keys) {
                  CompletableFuture<?> existingTask = this.queue.get(key);
                  if (existingTask != null) {
                      existingTasks.add(existingTask);
                  }
  
                  // Also include any currently executing filter tasks.
                  for (val e : this.filterQueue.entrySet()) {
                      if (e.getKey().test(key)) {
                          existingTasks.add(e.getValue());
                      }
                  }
              }
  
              executeAfterIfNeeded(existingTasks, toRun, result);
  
              // Update the queues for each key to point to the latest task.
              keys.forEach(key -> this.queue.put(key, result));
          }
  
          executeNowIfNeeded(existingTasks, toRun, result);
  
          // Cleanup: if this was the last task in the queue, then clean up the queue.
          result.whenComplete((r, ex) -> cleanup(keys));
          return result;
      }
docs: Queues up a new task to execute, subject to the given dependency Keys.
  
  This task will not begin execution until all previous tasks for the given dependency Keys have finished.
  In addition, no subsequent task for any of the given dependency Keys will begin executing until this task has
  finished executing.
  
  @param keys         A Collection of KeyType objects representing the Keys that this task is dependent on.
  @param toRun        A Supplier that will be invoked when it is this task's turn to run. It will return a
  CompletableFuture that will complete when this task completes.
  @param <ReturnType> Return type.
  @return A CompletableFuture that will complete with the result from the CompletableFuture returned by toRun,
  when toRun completes executing.