/**
   * Removes any tasks waiting to be run. Will not interrupt any tasks currently running if {@link
   * #tick(ExceptionHandlerInterface)} is being called. But will avoid additional tasks from being
   * run on the current {@link #tick(ExceptionHandlerInterface)} call.
   *
   * <p>If tasks are added concurrently during this invocation they may or may not be removed.
   *
   * @return List of runnables which were waiting in the task queue to be executed (and were now
   *     removed)
   */
  public List<Runnable> clearTasks() {
    List<TaskContainer> containers;
    synchronized (scheduledQueue.getModificationLock()) {
      containers = new ArrayList<TaskContainer>(executeQueue.size() + scheduledQueue.size());

      Iterator<? extends TaskContainer> it = executeQueue.iterator();
      while (it.hasNext()) {
        TaskContainer tc = it.next();
        /* we must use executeQueue.remove(Object) instead of it.remove()
         * This is to assure it is atomically removed (without executing)
         */
        if (!tc.running && executeQueue.remove(tc)) {
          int index = ListUtils.getInsertionEndIndex(containers, tc, true);
          containers.add(index, tc);
        }
      }

      it = scheduledQueue.iterator();
      while (it.hasNext()) {
        TaskContainer tc = it.next();
        if (!tc.running) {
          int index = ListUtils.getInsertionEndIndex(containers, tc, true);
          containers.add(index, tc);
        }
      }
      scheduledQueue.clear();
    }

    return ContainerHelper.getContainedRunnables(containers);
  }
  /**
   * Checks if there are tasks ready to be run on the scheduler. Generally this is called from the
   * same thread that would call {@link #tick(ExceptionHandlerInterface)} (but does not have to be).
   * If {@link #tick(ExceptionHandlerInterface)} is not currently being called, this call indicates
   * if the next {@link #tick(ExceptionHandlerInterface)} will have at least one task to run. If
   * {@link #tick(ExceptionHandlerInterface)} is currently being invoked, this call will do a best
   * attempt to indicate if there is at least one more task to run (not including the task which may
   * currently be running). It's a best attempt as it will try not to block the thread invoking
   * {@link #tick(ExceptionHandlerInterface)} to prevent it from accepting additional work.
   *
   * @return {@code true} if there are task waiting to run
   */
  public boolean hasTaskReadyToRun() {
    while (true) {
      TaskContainer nextExecuteTask = executeQueue.peek();
      if (nextExecuteTask != null) {
        if (nextExecuteTask.running) {
          // loop and retry, should be removed from queue shortly
          Thread.yield();
        } else {
          return true;
        }
      } else {
        break;
      }
    }

    synchronized (scheduledQueue.getModificationLock()) {
      Iterator<TaskContainer> it = scheduledQueue.iterator();
      while (it.hasNext()) {
        TaskContainer scheduledTask = it.next();
        if (scheduledTask.running) {
          continue;
        } else if (scheduledTask.getDelayInMillis() <= 0) {
          return true;
        } else {
          return false;
        }
      }
    }

    return false;
  }
  /**
   * Adds a task to scheduled/recurring queue. This call is more expensive than {@link
   * #addImmediateExecute(OneTimeTask)}, but is necessary for any tasks which are either delayed or
   * recurring.
   *
   * @param runnable Task to execute on next {@link #tick(ExceptionHandlerInterface)} call
   */
  protected void addScheduled(TaskContainer runnable) {
    synchronized (scheduledQueue.getModificationLock()) {
      ClockWrapper.stopForcingUpdate();
      try {
        int insertionIndex = ListUtils.getInsertionEndIndex(scheduledQueue, runnable, true);

        scheduledQueue.add(insertionIndex, runnable);
      } finally {
        ClockWrapper.resumeForcingUpdate();
      }
    }

    notifyQueueUpdate();
  }
 /**
  * Call to get the next task that is ready to be run. If there are no tasks, or the next task
  * still has a remaining delay, this will return {@code null}.
  *
  * <p>If this is being called in parallel with a {@link #tick(ExecutionHandlerInterface)} call,
  * the returned task may already be running. You must check the {@code TaskContainer.running}
  * boolean if this condition is important to you.
  *
  * @param onlyReturnReadyTask {@code false} to return scheduled tasks which may not be ready for
  *     execution
  * @return next ready task, or {@code null} if there are none
  */
 protected TaskContainer getNextTask(boolean onlyReturnReadyTask) {
   TaskContainer nextScheduledTask = scheduledQueue.peekFirst();
   TaskContainer nextExecuteTask = executeQueue.peek();
   if (nextExecuteTask != null) {
     if (nextScheduledTask != null) {
       long scheduleDelay;
       long executeDelay;
       ClockWrapper.stopForcingUpdate();
       try {
         scheduleDelay = nextScheduledTask.getDelayInMillis();
         executeDelay = nextExecuteTask.getDelayInMillis();
       } finally {
         ClockWrapper.resumeForcingUpdate();
       }
       if (scheduleDelay < executeDelay) {
         return nextScheduledTask;
       } else {
         return nextExecuteTask;
       }
     } else {
       return nextExecuteTask;
     }
   } else if (!onlyReturnReadyTask
       || (nextScheduledTask != null && nextScheduledTask.getDelayInMillis() <= 0)) {
     return nextScheduledTask;
   } else {
     return null;
   }
 }
 @Override
 public boolean remove(Callable<?> task) {
   if (ContainerHelper.remove(executeQueue, task)) {
     return true;
   }
   synchronized (scheduledQueue.getModificationLock()) {
     return ContainerHelper.remove(scheduledQueue, task);
   }
 }