EdtSinkProcessor { public void processSingle(@NotNull Callable<E> producer, boolean runEdtAsync) { ApplicationManager.getApplication().executeOnPooledThread(() -> { onStart(runEdtAsync); E value; try { value = producer.call(); consumeOne(value, runEdtAsync); consumeBatch(Collections.singletonList(value), runEdtAsync); } catch (Exception e) { LOG.info(e); onError(e, runEdtAsync); } onEnd(runEdtAsync); }); }  void addConsumer(@NotNull Consumer<E> consumer); void addBatchConsumer(@NotNull Consumer<Collection<E>> consumer); void addIcon(@NotNull final AsyncProcessIcon icon); void addDisabledWhileRunningComponent(@NotNull final JComponent component); void addStarter(@NotNull Runnable runner); void addFinalizer(@NotNull Runnable runner); void addErrorHandler(@NotNull Consumer<Throwable> consumer); void process(@NotNull final Producer<E> producer,
            @Nullable final ProgressIndicator progress,
            final int batchSize, final boolean runEdtAsync); void processSingle(@NotNull Callable<E> producer, boolean runEdtAsync); void processBatchAnswer(@NotNull Callable<Answer<List<E>>> producer, boolean runEdtAsync);  }
@Test void processSingle_callable_noListeners_noRunners_edtBackground() { MockThreadRunner mtr = new MockThreadRunner(idea); EdtSinkProcessor<Object> ecp = new EdtSinkProcessor<>(); mtr.setNextWaitKey("pooled-1"); Object returned = new Object(); ecp.processSingle(() -> returned, true); mtr.startAndWaitFor("pooled-1"); mtr.assertNoExceptions(); assertEquals(1, mtr.getPooledThreadsRunCount()); assertEquals(0, mtr.getEdtLaterRunCount()); assertEquals(0, mtr.getEdtWaitRunCount()); }