@Test public void workerIdleTest() { final Worker w = new Worker(workerPool, workerPool.threadFactory); w.start(); // wait for worker to become idle new TestCondition(() -> workerPool.idleWorker.get(), (o) -> o == w).blockTillTrue(); workerPool.startShutdown(); workerPool.finishShutdown(); // verify idle worker is gone new TestCondition(() -> workerPool.idleWorker.get() == null).blockTillTrue(); // should return immediately now that we are shut down workerPool.workerIdle(new Worker(workerPool, workerPool.threadFactory)); } }
/** * Adds the ready TaskWrapper to the correct schedule queue. Using the priority specified in the * task, we pick the correct queue and add it. * <p> * If this is just a single execution with no delay use {@link #addToExecuteQueue(OneTimeTaskWrapper)}. * * @param task {@link TaskWrapper} to queue for the scheduler */ protected void addToScheduleQueue(QueueSet queueSet, TaskWrapper task) { if (workerPool.isShutdownStarted()) { throw new RejectedExecutionException("Thread pool shutdown"); } queueSet.addScheduled(task); }
@Override public TaskWrapper workerIdle(Worker worker) { TaskWrapper result = super.workerIdle(worker); // may not be a wrapper for internal tasks like shutdown if (result != null && result.getContainedRunnable() instanceof TaskStatWrapper) { long taskDelay = Clock.lastKnownForwardProgressingMillis() - result.getPureRunTime(); TaskStatWrapper statWrapper = (TaskStatWrapper)result.getContainedRunnable(); ConcurrentArrayList<Long> priorityStats = statsManager.getExecutionDelaySamplesInternal(statWrapper.priority); synchronized (priorityStats.getModificationLock()) { priorityStats.add(taskDelay); statsManager.trimWindow(priorityStats); } } return result; } }
@Override public TaskWrapper workerIdle(Worker worker) { TaskWrapper result = super.workerIdle(worker); // may not be a wrapper for internal tasks like shutdown if (result != null && result.getContainedRunnable() instanceof TaskStatWrapper) { long taskDelay = Clock.lastKnownForwardProgressingMillis() - result.getPureRunTime(); TaskStatWrapper statWrapper = (TaskStatWrapper)result.getContainedRunnable(); ConcurrentArrayList<Long> priorityStats = statsManager.getExecutionDelaySamplesInternal(statWrapper.priority); synchronized (priorityStats.getModificationLock()) { priorityStats.add(taskDelay); statsManager.trimWindow(priorityStats); } } return result; } }
/** * Constructs a new thread pool, though no threads will be started till it accepts it's first * request. This provides the extra parameters to tune what tasks submitted without a priority * will be scheduled as. As well as the maximum wait for low priority tasks. The longer low * priority tasks wait for a worker, the less chance they will have to create a thread. But it * also makes low priority tasks execution time less predictable. * * @param poolSize Thread pool size that should be maintained * @param defaultPriority priority to give tasks which do not specify it * @param maxWaitForLowPriorityInMs time low priority tasks wait for a worker * @param threadFactory thread factory for producing new threads within executor */ public StrictPriorityScheduler(int poolSize, TaskPriority defaultPriority, long maxWaitForLowPriorityInMs, ThreadFactory threadFactory) { super(new WorkerPool(threadFactory, poolSize), defaultPriority, maxWaitForLowPriorityInMs); }
/** * Change the set thread pool size. * <p> * If the value is less than the current running threads, as threads finish they will exit * rather than accept new tasks. No currently running tasks will be interrupted, rather we * will just wait for them to finish before killing the thread. * <p> * If this is an increase in the pool size, threads will be lazily started as needed till the * new size is reached. If there are tasks waiting for threads to run on, they immediately * will be started. * * @param newPoolSize New core pool size, must be at least one */ public void setPoolSize(int newPoolSize) { workerPool.setPoolSize(newPoolSize); }
/** * Stops any new tasks from being able to be executed and removes workers from the pool. * <p> * This implementation refuses new submissions after this call. And will NOT interrupt any * tasks which are currently running. However any tasks which are waiting in queue to be run * (but have not started yet), will not be run. Those waiting tasks will be removed, and as * workers finish with their current tasks the threads will be joined. * * @return List of runnables which were waiting to execute */ public List<Runnable> shutdownNow() { workerPool.startShutdown(); List<Runnable> awaitingTasks = taskQueueManager.clearQueue(); workerPool.finishShutdown(); return awaitingTasks; }
/** * This constructor is designed for extending classes to be able to provide their own * implementation of {@link WorkerPool}. Ultimately all constructors will defer to this one. * * @param workerPool WorkerPool to handle accepting tasks and providing them to a worker for execution * @param defaultPriority Default priority to store in case no priority is provided for tasks * @param maxWaitForLowPriorityInMs time low priority tasks to wait if there are high priority tasks ready to run */ protected PriorityScheduler(WorkerPool workerPool, TaskPriority defaultPriority, long maxWaitForLowPriorityInMs) { super(defaultPriority); this.workerPool = workerPool; taskQueueManager = new QueueManager(workerPool, maxWaitForLowPriorityInMs); workerPool.start(taskQueueManager); }
/** * Constructs a new thread pool, though threads will be lazily started as it has tasks ready to * run. This provides the extra parameters to tune what tasks submitted without a priority * will be scheduled as. As well as the maximum wait for low priority tasks. * * @param poolSize Thread pool size that should be maintained * @param defaultPriority Default priority for tasks which are submitted without any specified priority * @param maxWaitForLowPriorityInMs time low priority tasks to wait if there are high priority tasks ready to run * @param threadFactory thread factory for producing new threads within executor */ public PriorityScheduler(int poolSize, TaskPriority defaultPriority, long maxWaitForLowPriorityInMs, ThreadFactory threadFactory) { this(new WorkerPool(threadFactory, poolSize), defaultPriority, maxWaitForLowPriorityInMs); }
/** * 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)); } }
/** * Stops any new tasks from being able to be executed and removes workers from the pool. * <p> * This implementation refuses new submissions after this call. And will NOT interrupt any * tasks which are currently running. However any tasks which are waiting in queue to be run * (but have not started yet), will not be run. Those waiting tasks will be removed, and as * workers finish with their current tasks the threads will be joined. * * @return List of runnables which were waiting to execute */ public List<Runnable> shutdownNow() { workerPool.startShutdown(); List<Runnable> awaitingTasks = taskQueueManager.clearQueue(); workerPool.finishShutdown(); return awaitingTasks; }
/** * Constructs a new thread pool, though threads will be lazily started as it has tasks ready to * run. This provides the extra parameters to tune what tasks submitted without a priority * will be scheduled as. As well as the maximum wait for low priority tasks. * * @param poolSize Thread pool size that should be maintained * @param defaultPriority Default priority for tasks which are submitted without any specified priority * @param maxWaitForLowPriorityInMs time low priority tasks to wait if there are high priority tasks ready to run * @param threadFactory thread factory for producing new threads within executor */ public PriorityScheduler(int poolSize, TaskPriority defaultPriority, long maxWaitForLowPriorityInMs, ThreadFactory threadFactory) { this(new WorkerPool(threadFactory, poolSize), defaultPriority, maxWaitForLowPriorityInMs); }
/** * 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)); } }
/** * This constructor is designed for extending classes to be able to provide their own * implementation of {@link WorkerPool}. Ultimately all constructors will defer to this one. * * @param workerPool WorkerPool to handle accepting tasks and providing them to a worker for execution * @param defaultPriority Default priority to store in case no priority is provided for tasks * @param maxWaitForLowPriorityInMs time low priority tasks to wait if there are high priority tasks ready to run */ protected PriorityScheduler(WorkerPool workerPool, TaskPriority defaultPriority, long maxWaitForLowPriorityInMs) { super(defaultPriority); this.workerPool = workerPool; taskQueueManager = new QueueManager(workerPool, maxWaitForLowPriorityInMs); workerPool.start(taskQueueManager); }
/** * Adds the ready TaskWrapper to the correct schedule queue. Using the priority specified in the * task, we pick the correct queue and add it. * <p> * If this is just a single execution with no delay use {@link #addToExecuteQueue(OneTimeTaskWrapper)}. * * @param task {@link TaskWrapper} to queue for the scheduler */ protected void addToScheduleQueue(QueueSet queueSet, TaskWrapper task) { if (workerPool.isShutdownStarted()) { throw new RejectedExecutionException("Thread pool shutdown"); } queueSet.addScheduled(task); }
/** * Change the set thread pool size. * <p> * If the value is less than the current running threads, as threads finish they will exit * rather than accept new tasks. No currently running tasks will be interrupted, rather we * will just wait for them to finish before killing the thread. * <p> * If this is an increase in the pool size, threads will be lazily started as needed till the * new size is reached. If there are tasks waiting for threads to run on, they immediately * will be started. * * @param newPoolSize New core pool size, must be at least one */ public void setPoolSize(int newPoolSize) { workerPool.setPoolSize(newPoolSize); }
/** * 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); }
/** * 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); }
@Override public boolean isShutdown() { return workerPool.isShutdownStarted(); }
@Override public boolean isShutdown() { return workerPool.isShutdownStarted(); }