public void execute(final PrioritizableRunnable runnable) {
    _queue.add(runnable);
    // Guarantees that execution loop is scheduled only once to the underlying executor.
    // Also makes sure that all memory effects of last Runnable are visible to the next Runnable
    // in case value returned by decrementAndGet == 0.
    if (_pendingCount.getAndIncrement() == 0) {
      tryExecuteLoop();
    }
  }
@Test(dataProvider = "draining")
  public void testRejectOnLoop(boolean draining) throws InterruptedException {
    final CountDownLatch innerLatch = new CountDownLatch(1);
    final CountDownLatch outerLatch = new CountDownLatch(1);
    final LatchedRunnable inner = new LatchedRunnable();
    final LatchedRunnable outer = new LatchedRunnable() {
      @Override
      public void run() {
        try {
          outerLatch.countDown();
          innerLatch.await();
          _serialExecutor.execute(inner);
        } catch (InterruptedException e) {
          // Shouldn't happen
        }
        super.run();
      }
    };

    // First we submit the outer task. This task will wait until for a count
    // down on the inner latch.
    _serialExecutor.execute(outer);
    outerLatch.await();

    // Now we submit another runnable to the underlying executor. This should
    // get queued up.
    _executorService.execute(new NeverEndingRunnable());

    // Now the inner task will be submitted. This will eventually result in
    // the re-execution of the serial executor loop, but that re-submission will
    // fail because the thread is tied up by the current loop and the queue is
    // saturated with the previously submitted runnable.
    innerLatch.countDown();

    if (!draining) {
      assertTrue(_rejectionHandler.await(5, TimeUnit.SECONDS));
      assertTrue(
          "Expected " + _rejectionHandler.getLastError() + " to be instance of "
              + RejectedExecutionException.class.getName(),
          _rejectionHandler.getLastError() instanceof RejectedExecutionException);
    } else {
      assertFalse(_rejectionHandler.wasExecuted());
    }
  }