@Override
  public void shutdown() {
    threadPoolExecutor.shutdown();
    synchronized (tasks) {
      // Notify tasks which checks to see if the ThreadPoolExecutor is shutdown and exits cleanly.
      tasks.notify();
    }

    // Re-throw any errors during shutdown of the launchTasks thread.
    try {
      launchTasks.get();
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      throw new RuntimeException(e);
    } catch (ExecutionException e) {
      throw new RuntimeException(e.getCause());
    }
  }
@Test
  public void testShutdown() throws Exception {
    FastNanoClockAndSleeper fastNanoClockAndSleeper = new FastNanoClockAndSleeper();
    UnboundedScheduledExecutorService executorService =
        new UnboundedScheduledExecutorService(fastNanoClockAndSleeper);

    Runnable runnable1 = Mockito.mock(Runnable.class);
    Runnable runnable2 = Mockito.mock(Runnable.class);
    Runnable runnable3 = Mockito.mock(Runnable.class);
    Callable<?> callable1 = Mockito.mock(Callable.class);

    Future<?> rFuture1 = executorService.schedule(runnable1, 10, SECONDS);
    Future<?> cFuture1 = executorService.schedule(callable1, 10, SECONDS);
    Future<?> rFuture2 = executorService.scheduleAtFixedRate(runnable2, 10, 10, SECONDS);
    Future<?> rFuture3 = executorService.scheduleWithFixedDelay(runnable3, 10, 10, SECONDS);

    assertThat(
        executorService.shutdownNow(),
        IsIterableContaining.hasItems(
            (Runnable) rFuture1, (Runnable) rFuture2, (Runnable) rFuture3, (Runnable) cFuture1));
    verifyNoInteractions(runnable1, runnable2, runnable3, callable1);

    assertTrue(executorService.isShutdown());
    assertTrue(executorService.awaitTermination(10, SECONDS));
    assertTrue(executorService.isTerminated());
  }