boolean (@NotNull final Iterator<T> subClassIterator) { // Found nothing, have to wait for other threads because: // The first thread comes and takes a class off the queue to search for inheritors, // the second thread comes and sees there is no classes in the queue. // The second thread should not return nothing, it should wait for the first thread to finish instead. // // Wait within managedBlock to signal FJP this thread is locked (to avoid thread starvation and deadlocks) AtomicBoolean hasNext = new AtomicBoolean(); try { ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() { @Override public boolean block() { while (!currentlyProcessingClasses.isUp()) { ProgressManager.checkCanceled(); currentlyProcessingClasses.waitFor(1); // wait until other threads process their classes before giving up } return isReleasable(); } @Override public boolean isReleasable() { synchronized (lock) { // other thread produced something or all of them reached the end of list boolean producedSomething = subClassIterator.hasNext(); hasNext.set(producedSomething); // store the result to avoid locking again after exit return producedSomething || !candidatesToFindSubclassesIterator.hasNext() || classesBeingProcessed.isEmpty(); } } }); } catch (InterruptedException e) { throw new RuntimeException(e); } return hasNext.get(); }