private void startTaskWorkers() {
    if (!Registry.is("batch.inspections.process.project.usages.in.parallel")) {
      return;
    }
    final int setting = Registry.get("batch.inspections.number.of.threads").asInteger();
    final int threadsCount = (setting > 0) ? setting : Runtime.getRuntime().availableProcessors() - 1;
    if (threadsCount == 0) {
      // need more than 1 core for parallel processing
      return;
    }
    LOG.info("Processing project usages using " + threadsCount + " threads");
    // unbounded queue because tasks are submitted under read action, so we mustn't block
    myTasks = new LinkedBlockingQueue<>();
    myFutures = new ArrayList<>();
    final Application application = ApplicationManager.getApplication();
    final ProgressManager progressManager = ProgressManager.getInstance();
    final ProgressIndicator progressIndicator = progressManager.getProgressIndicator();
    for (int i = 0; i < threadsCount; i++) {
      final Future<?> future = application.executeOnPooledThread(() -> {
        while (myFutures != null || !myTasks.isEmpty()) {
          try {
            final Runnable task = myTasks.poll(50, TimeUnit.MILLISECONDS);
            ProgressManager.checkCanceled();
            if (task != null) {
              runTask(progressIndicator, task);
            }
          }
          catch (InterruptedException ignore) {}
        }
      });
      myFutures.add(future);
    }
  }
private void startTaskWorkers()