/** * Adds the ready TaskWrapper to the correct execute queue. Using the priority specified in the * task, we pick the correct queue and add it. * <p> * If this is a scheduled or recurring task use {@link #addToScheduleQueue(TaskWrapper)}. * * @param task {@link TaskWrapper} to queue for the scheduler */ protected void addToExecuteQueue(QueueSet queueSet, OneTimeTaskWrapper task) { if (workerPool.isShutdownStarted()) { throw new RejectedExecutionException("Thread pool shutdown"); } queueSet.addExecute(task); }
@Test public void addScheduledOrderTest() { List<TaskWrapper> orderedList = new ArrayList<>(TEST_QTY); for (int i = 0; i < TEST_QTY; i++) { orderedList.add(new OneTimeTaskWrapper(DoNothingRunnable.instance(), null, Clock.accurateForwardProgressingMillis() + i)); } List<TaskWrapper> randomList = new ArrayList<>(orderedList); Collections.shuffle(randomList); Iterator<TaskWrapper> it = randomList.iterator(); while (it.hasNext()) { queueSet.addScheduled(it.next()); } Iterator<TaskWrapper> expectedIt = orderedList.iterator(); Iterator<TaskWrapper> resultIt = queueSet.scheduleQueue.iterator(); while (expectedIt.hasNext()) { assertTrue(expectedIt.next() == resultIt.next()); } }
/** * Removes any tasks waiting to be run. Will not interrupt any tasks currently running. But * will avoid additional tasks from being run (unless they are allowed to be added during or * after this 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> clearQueue() { List<TaskWrapper> wrapperList = new ArrayList<>(highPriorityQueueSet.queueSize() + lowPriorityQueueSet.queueSize() + starvablePriorityQueueSet.queueSize()); highPriorityQueueSet.drainQueueInto(wrapperList); lowPriorityQueueSet.drainQueueInto(wrapperList); starvablePriorityQueueSet.drainQueueInto(wrapperList); return ContainerHelper.getContainedRunnables(wrapperList); }
TaskWrapper nextHighPriorityTask = highPriorityQueueSet.getNextTask(); TaskWrapper nextLowPriorityTask = lowPriorityQueueSet.getNextTask(); if (nextLowPriorityTask == null) { nextTask = nextHighPriorityTask; return starvablePriorityQueueSet.getNextTask(); } else { long nextTaskDelay = nextTask.getScheduleDelay(); if (nextTaskDelay > 0) { TaskWrapper nextStarvableTask = starvablePriorityQueueSet.getNextTask(); if (nextStarvableTask != null && nextStarvableTask.getPureRunTime() < nextTask.getPureRunTime()) {
TaskWrapper nextHighPriorityTask = highPriorityQueueSet.getNextTask(); TaskWrapper nextLowPriorityTask = lowPriorityQueueSet.getNextTask(); if (nextLowPriorityTask == null) { nextTask = nextHighPriorityTask; return starvablePriorityQueueSet.getNextTask(); } else { long nextTaskDelay = nextTask.getScheduleDelay(); if (nextTaskDelay > 0) { TaskWrapper nextStarvableTask = starvablePriorityQueueSet.getNextTask(); if (nextStarvableTask != null && nextStarvableTask.getPureRunTime() < nextTask.getPureRunTime()) {
/** * Used for gaining compatibility with java.util.concurrent when a {@link Delayed} object is * needed. * * @param scheduler Scheduler to submit task to * @param task Task to be submitted * @param priority Priority for task to be submitted at * @param initialDelay initial delay for task to execute * @param delayInMs recurring delay for task to execute * @return Delayed implementation which corresponds to executed task */ public static Delayed doScheduleWithFixedDelayAndGetDelayed(SingleThreadScheduler scheduler, Runnable task, TaskPriority priority, long initialDelay, long delayInMs) { NoThreadScheduler nts = scheduler.getRunningScheduler(); QueueSet queueSet = nts.queueManager.getQueueSet(priority); NoThreadRecurringDelayTaskWrapper rdt = nts.new NoThreadRecurringDelayTaskWrapper(task, queueSet, Clock.accurateForwardProgressingMillis() + initialDelay, delayInMs); queueSet.addScheduled(rdt); return new DelayedTaskWrapper(rdt); }
/** * Used for gaining compatibility with java.util.concurrent when a {@link Delayed} object is * needed. * * @param scheduler Scheduler to submit task to * @param task Task to be submitted * @param priority Priority for task to be submitted at * @param initialDelay initial delay for task to execute * @param periodInMillis recurring delay for task to execute * @return Delayed implementation which corresponds to executed task */ public static Delayed doScheduleAtFixedRateAndGetDelayed(SingleThreadScheduler scheduler, Runnable task, TaskPriority priority, long initialDelay, long periodInMillis) { NoThreadScheduler nts = scheduler.getRunningScheduler(); QueueSet queueSet = nts.queueManager.getQueueSet(priority); NoThreadRecurringRateTaskWrapper rt = nts.new NoThreadRecurringRateTaskWrapper(task, queueSet, Clock.accurateForwardProgressingMillis() + initialDelay, periodInMillis); queueSet.addScheduled(rt); return new DelayedTaskWrapper(rt); }
/** * Used for gaining compatibility with java.util.concurrent when a {@link Delayed} object is * needed. * * @param scheduler Scheduler to submit task to * @param task Task to be submitted * @param priority Priority for task to be submitted at * @param initialDelay initial delay for task to execute * @param periodInMillis recurring delay for task to execute * @return Delayed implementation which corresponds to executed task */ public static Delayed doScheduleAtFixedRateAndGetDelayed(SingleThreadScheduler scheduler, Runnable task, TaskPriority priority, long initialDelay, long periodInMillis) { NoThreadScheduler nts = scheduler.getRunningScheduler(); QueueSet queueSet = nts.queueManager.getQueueSet(priority); NoThreadRecurringRateTaskWrapper rt = nts.new NoThreadRecurringRateTaskWrapper(task, queueSet, Clock.accurateForwardProgressingMillis() + initialDelay, periodInMillis); queueSet.addScheduled(rt); return new DelayedTaskWrapper(rt); }
/** * Used for gaining compatibility with java.util.concurrent when a {@link Delayed} object is * needed. * * @param scheduler Scheduler to submit task to * @param task Task to be submitted * @param priority Priority for task to be submitted at * @param initialDelay initial delay for task to execute * @param delayInMs recurring delay for task to execute * @return Delayed implementation which corresponds to executed task */ public static Delayed doScheduleWithFixedDelayAndGetDelayed(SingleThreadScheduler scheduler, Runnable task, TaskPriority priority, long initialDelay, long delayInMs) { NoThreadScheduler nts = scheduler.getRunningScheduler(); QueueSet queueSet = nts.queueManager.getQueueSet(priority); NoThreadRecurringDelayTaskWrapper rdt = nts.new NoThreadRecurringDelayTaskWrapper(task, queueSet, Clock.accurateForwardProgressingMillis() + initialDelay, delayInMs); queueSet.addScheduled(rdt); return new DelayedTaskWrapper(rdt); }
@Test public void getDelayTillNextTaskTest() { assertEquals(Long.MAX_VALUE, scheduler.getDelayTillNextTask()); // schedule in the future scheduler.schedule(DoNothingRunnable.instance(), 1000 * 15); // still should have nothing ready to run assertTrue(scheduler.getDelayTillNextTask() > 0); scheduler.execute(DoNothingRunnable.instance()); // should now have tasks ready to run assertTrue(scheduler.getDelayTillNextTask() <= 0); scheduler.tick(null); // should no longer have anything to run assertTrue(scheduler.getDelayTillNextTask() > 0); scheduler.queueManager.highPriorityQueueSet .addScheduled(new OneTimeTaskWrapper(DoNothingRunnable.instance(), scheduler.queueManager.highPriorityQueueSet.scheduleQueue, Clock.lastKnownForwardProgressingMillis())); // now should be true with scheduled task which is ready to run assertTrue(scheduler.getDelayTillNextTask() <= 0); }
@Test public void hasTaskReadyToRunTest() { assertFalse(scheduler.hasTaskReadyToRun()); // schedule in the future scheduler.schedule(DoNothingRunnable.instance(), 1000 * 15); // still should have nothing ready to run assertFalse(scheduler.hasTaskReadyToRun()); scheduler.execute(DoNothingRunnable.instance()); // should now have tasks ready to run assertTrue(scheduler.hasTaskReadyToRun()); scheduler.tick(null); // should no longer have anything to run assertFalse(scheduler.hasTaskReadyToRun()); scheduler.queueManager.highPriorityQueueSet .addScheduled(new OneTimeTaskWrapper(DoNothingRunnable.instance(), scheduler.queueManager.highPriorityQueueSet.scheduleQueue, Clock.lastKnownForwardProgressingMillis())); // now should be true with scheduled task which is ready to run assertTrue(scheduler.hasTaskReadyToRun()); }
@Test public void getNextReadyTaskExecuteAheadOfScheduledTest() { OneTimeTaskWrapper executeTask = new OneTimeTaskWrapper(DoNothingRunnable.instance(), queueManager.highPriorityQueueSet.executeQueue, Clock.accurateForwardProgressingMillis()); queueManager.highPriorityQueueSet.addExecute(executeTask); TestUtils.blockTillClockAdvances(); TaskWrapper scheduleTask = new OneTimeTaskWrapper(DoNothingRunnable.instance(), queueManager.highPriorityQueueSet.scheduleQueue, Clock.lastKnownForwardProgressingMillis()); queueManager.highPriorityQueueSet.addScheduled(scheduleTask); assertTrue(executeTask == queueManager.getNextTask()); assertTrue(executeTask == queueManager.getNextTask()); // execute task has not been removed yet // this should remove the execute task so we can get the scheduled task assertTrue(executeTask.canExecute(executeTask.getExecuteReference())); assertTrue(scheduleTask == queueManager.getNextTask()); }
/** * Removes any tasks waiting to be run. Will not interrupt any tasks currently running. But * will avoid additional tasks from being run (unless they are allowed to be added during or * after this 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> clearQueue() { List<TaskWrapper> wrapperList = new ArrayList<>(highPriorityQueueSet.queueSize() + lowPriorityQueueSet.queueSize() + starvablePriorityQueueSet.queueSize()); highPriorityQueueSet.drainQueueInto(wrapperList); lowPriorityQueueSet.drainQueueInto(wrapperList); starvablePriorityQueueSet.drainQueueInto(wrapperList); return ContainerHelper.getContainedRunnables(wrapperList); }
/** * When ever pool state is changed that is not checked in the pollTask loop (ie shutdown state, * pool size), a task must be added that is continually added till the desired state is reached. * <p> * The purpose of this task is to break worker threads out of the tight loop for polling tasks, * and instead get them to check the initial logic in {@link #workerIdle(Worker)} again. This * is in contrast to putting the logic in the poll task loop, which only incurs a performance * penalty. */ private void addPoolStateChangeTask(InternalRunnable task) { // add to starvable queue, since we only need these tasks to be consumed and ran when there // is nothing else to run. queueManager.starvablePriorityQueueSet .addExecute(new ImmediateTaskWrapper(task, queueManager.starvablePriorityQueueSet.executeQueue)); }
@Test public void getNextReadyTaskScheduledAheadOfExecuteTest() { TaskWrapper scheduleTask = new OneTimeTaskWrapper(DoNothingRunnable.instance(), queueManager.highPriorityQueueSet.scheduleQueue, Clock.accurateForwardProgressingMillis()); queueManager.highPriorityQueueSet.addScheduled(scheduleTask); TestUtils.blockTillClockAdvances(); OneTimeTaskWrapper executeTask = new OneTimeTaskWrapper(DoNothingRunnable.instance(), queueManager.highPriorityQueueSet.executeQueue, Clock.lastKnownForwardProgressingMillis()); queueManager.highPriorityQueueSet.addExecute(executeTask); assertTrue(scheduleTask == queueManager.getNextTask()); assertTrue(scheduleTask == queueManager.getNextTask()); // schedule task has not been removed yet // this should remove the schedule task so we can get the execute task assertTrue(scheduleTask.canExecute(executeTask.getExecuteReference())); assertTrue(executeTask == queueManager.getNextTask()); }
@Override public void scheduleAtFixedRate(Runnable task, long initialDelay, long period, TaskPriority priority) { ArgumentVerifier.assertNotNull(task, "task"); ArgumentVerifier.assertNotNegative(initialDelay, "initialDelay"); ArgumentVerifier.assertGreaterThanZero(period, "period"); if (priority == null) { priority = defaultPriority; } QueueSet queueSet = queueManager.getQueueSet(priority); NoThreadRecurringRateTaskWrapper taskWrapper = new NoThreadRecurringRateTaskWrapper(task, queueSet, nowInMillis(true) + initialDelay, period); queueSet.addScheduled(taskWrapper); }
@Override public void scheduleAtFixedRate(Runnable task, long initialDelay, long period, TaskPriority priority) { ArgumentVerifier.assertNotNull(task, "task"); ArgumentVerifier.assertNotNegative(initialDelay, "initialDelay"); ArgumentVerifier.assertGreaterThanZero(period, "period"); if (priority == null) { priority = defaultPriority; } QueueSet queueSet = queueManager.getQueueSet(priority); NoThreadRecurringRateTaskWrapper taskWrapper = new NoThreadRecurringRateTaskWrapper(task, queueSet, nowInMillis(true) + initialDelay, period); queueSet.addScheduled(taskWrapper); }
/** * Stops any new tasks from being submitted to the pool. But allows all tasks which are * submitted to execute, or scheduled (and have elapsed their delay time) to run. If recurring * tasks are present they will also be unable to reschedule. If {@code shutdown()} or * {@link #shutdownNow()} has already been called, this will have no effect. * <p> * If you wish to not want to run any queued tasks you should use {@link #shutdownNow()}. */ public void shutdown() { if (workerPool.startShutdown()) { ShutdownRunnable sr = new ShutdownRunnable(workerPool); taskQueueManager.lowPriorityQueueSet .addExecute(new ImmediateTaskWrapper(sr, taskQueueManager.lowPriorityQueueSet.executeQueue)); } }
/** * When ever pool state is changed that is not checked in the pollTask loop (ie shutdown state, * pool size), a task must be added that is continually added till the desired state is reached. * <p> * The purpose of this task is to break worker threads out of the tight loop for polling tasks, * and instead get them to check the initial logic in {@link #workerIdle(Worker)} again. This * is in contrast to putting the logic in the poll task loop, which only incurs a performance * penalty. */ private void addPoolStateChangeTask(InternalRunnable task) { // add to starvable queue, since we only need these tasks to be consumed and ran when there // is nothing else to run. queueManager.starvablePriorityQueueSet .addExecute(new ImmediateTaskWrapper(task, queueManager.starvablePriorityQueueSet.executeQueue)); }
/** * Removes the runnable task from the execution queue. It is possible for the runnable to * still run until this call has returned. * <p> * Note that this call has high guarantees on the ability to remove the task (as in a complete * guarantee). But while this is being invoked, it will reduce the throughput of execution, * so should NOT be used extremely frequently. * * @param task The original runnable provided to the executor * @return {@code true} if the runnable was found and removed */ public boolean remove(Runnable task) { return highPriorityQueueSet.remove(task) || lowPriorityQueueSet.remove(task) || starvablePriorityQueueSet.remove(task); }