/** * 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; }
@Override public boolean remove(Callable<?> task) { if (ContainerHelper.remove(executeQueue, task)) { return true; } synchronized (scheduledQueue.getModificationLock()) { return ContainerHelper.remove(scheduledQueue, task); } }
/** * 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(); }