private void processMoreSubclasses(@NotNull Iterator<T> subClassIterator) {
    while (true) {
      ProgressManager.checkCanceled();

      Pair.NonNull<T,V> pair =
        ReadAction.compute(() -> {
          ProgressManager.checkCanceled();
          synchronized (lock) {
            // Find the classes in subClasses collection to operate on
            // (without advancing the candidatesToFindSubclassesIterator iterator - it will be moved after the class successfully handled - to protect against PCE, INRE, etc.)
            // The found class will be marked as being analyzed - placed in classesBeingProcessed collection
            HashSetQueue.PositionalIterator.IteratorPosition<T> startPosition = candidatesToFindSubclassesIterator.position().next();
            Pair.NonNull<T,V> next = startPosition == null ? null : findNextClassInQueue(startPosition);
            if (next != null) {
              currentlyProcessingClasses.down();
              classesBeingProcessed.add(next.getFirst());
            }
            return next;
          }
        });
      if (pair == null) {
        // no candidates left in queue, exit
        // but first, wait for other threads to process their candidates
        synchronized (lock) {
          advanceIteratorOnSuccess(); // to skip unsuitable classes like final etc from the queue
          if (subClassIterator.hasNext()) {
            return;
          }
        }

        boolean producedSomething = waitForOtherThreadsToFinishProcessing(subClassIterator);
        if (producedSomething) {
          return;
        }

        // aaaaaaaa! Other threads were unable to produce anything. That can be because:
        // - the whole queue has been processed. => exit, return false
        // - the other thread has been interrupted. => check the queue again to pick up the work it dropped.
        synchronized (lock) {
          advanceIteratorOnSuccess(); // to skip unsuitable classes like final etc from the queue
          if (!candidatesToFindSubclassesIterator.hasNext()) {
            return;
          }
        }

        continue; // check again
      }

      V candidate = pair.getSecond();
      T anchor = pair.getFirst();
      try {
        myGenerator.generateMoreElementsFor(candidate, generatedElement -> {
          ProgressManager.checkCanceled();
          synchronized (lock) {
            subClasses.add(generatedElement);
          }
        });
        synchronized (lock) {
          classesProcessed.add(anchor);
          advanceIteratorOnSuccess();
          if (subClassIterator.hasNext()) {
            // we've added something to subClasses, so we can return and the iterator can move forward at least once;
            // more elements will be added on the subsequent call to .next()
            return;
          }
        }
      }
      finally {
        synchronized (lock) {
          classesBeingProcessed.remove(anchor);
          currentlyProcessingClasses.up();
        }
      }
    }
  }
private void processMoreSubclasses(@NotNull Iterator<T> subClassIterator)