public <T> void notifyReadyAsync(Callable<T> callable, BiConsumer<T, Throwable> handler) {
        workerExecutor.execute(
                () -> {
                    try {
                        T result = callable.call();
                        executorToNotify.execute(() -> handler.accept(result, null));
                    } catch (Throwable t) {
                        executorToNotify.execute(() -> handler.accept(null, t));
                    }
                });
    }
@Test
    public void testExceptionInHandlerWhenHandlingException() throws InterruptedException {
        Exception exception1 = new Exception("Expected exception.");
        RuntimeException exception2 = new RuntimeException("Expected exception.");
        CountDownLatch latch = new CountDownLatch(1);
        notifier.notifyReadyAsync(
                () -> {
                    throw exception1;
                },
                (v, e) -> {
                    assertEquals(exception1, e);
                    assertNull(v);
                    latch.countDown();
                    throw exception2;
                });
        latch.await();
        // The uncaught exception handler may fire after the executor has shutdown.
        // We need to wait on the countdown latch here.
        exceptionInHandlerLatch.await(10000L, TimeUnit.MILLISECONDS);
        assertEquals(exception2, exceptionInHandler);
    }