I'm using the Spring (v4) ThreadPoolTaskExecutor to execute some continuous runnable tasks. When the application shuts down, I want a graceful shutdown of the executor so that tasks have some time to complete their iteration before continuing the shutdown. If an active task completes its iteration prior to the executors wait time expiring (e.g. ThreadPoolTaskExecutor.setAwaitTerminationSeconds()), I do not want it to start another iteration. So far I have not been able to accomplish this. I have the following executor configuration:
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(30);
And my tasks are essentially setup as such:
myExecutor.execute(() -> {
while(true) {
doSomething();
}
});
I assume I need to set a flag in my thread when the executor shuts down so that the loop breaks. Is there another recommended approach?
Your run method is a endless loop, so you don't need to
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(30);
After removing above code, when you shutdown the thread pool, your working thread will be marked as iterrupted immediatly, but they will continue their work(unless they are sleeping, or InterruptionException will be thrown), and tasks in the cache queue will not be executed. You can just check this state and do not start next iteration.
myExecutor.execute(() -> {
while(true && !Thread.currentThread().isInterrupted()) {
doSomething();
}
});
Related
I'm trying to have a single thread loading records (say from a database). This thread feeds records into a thread pool that processes these individual tasks.
I was expecting this code to work, but it prints number until 60 and then stops.
ThreadPoolTaskExecutor accountLoaderTaskExecutor = new ThreadPoolTaskExecutor();
accountLoaderTaskExecutor.setCorePoolSize(1);
accountLoaderTaskExecutor.setMaxPoolSize(1);
accountLoaderTaskExecutor.initialize();
ThreadPoolTaskExecutor accountDeletionTaskExecutor = new ThreadPoolTaskExecutor();
accountDeletionTaskExecutor.setCorePoolSize(10);
accountDeletionTaskExecutor.setMaxPoolSize(10);
accountDeletionTaskExecutor.setQueueCapacity(50);
accountDeletionTaskExecutor.initialize();
accountLoaderTaskExecutor.submit(() -> {
List<Integer> customerAccountIds = getCustomerAccountIds(); // return 1000s integers
customerAccountIds.forEach(id -> {
accountDeletionTaskExecutor.submit(() -> {
try {
System.out.println(id);
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
});
});
Thread.currentThread().join();
I was expecting the accountLoaderTaskExecutor thread to block on accountDeletionTaskExecutor.submit but then continue as records are being processed until it exhausts all customerAccountIds.
If that comment "return 1000s integers" means that you have thousands of ids, then the code you have written will queue thousands of tasks to the threadpool and then proceed to Thread.currentThread().join() which does absolutely nothing, because joining the current thread to itself is meaningless: you can only join different threads.
Then, I presume you exit the application, and the default behavior is probably to terminate all threadpools on application exit. (I am not sure about that, I am speculating.)
The 60 tasks that you observe getting started probably manage to start while the remaining thousands of tasks are being queued.
To verify that this is what is happening, you can try replacing that call to join() with a Thread.sleep( 1000 ) and see if you observe more tasks being started.
If that is the case, then one approach to solve your problem might be to add proper graceful threadpool shut-down (of the kind that waits for all queued tasks to complete first.)
I'm developing a gui-less desktop application for my company that is planned to be always running in the background retrieving info from websites (through HtmlUnit) and updating some rows in the data base.
I'm using a ExecutorService to submit tasks where the web site is loaded so I can set a timeout. This way:
private ExecutorService taskExecutor = Executors.newFixedThreadPool(1);
private long timeout = 60000L;
private Page loadSite(Loader<Page> c) {
Page page;
Future<Page> result = taskExecutor.submit(c);
try {
page = result.get(timeout, TimeUnit.MILLISECONDS);
} catch (TimeoutException | ExecutionException | InterruptedException ex) {
close();
result.cancel(true);
throw new HandledWebException(ex);
}
return page.getEnclosingWindow().getEnclosedPage();
}
The questions are:
Should I check if my taskExecutor object is able to schedule a task before the submit call, and reinstantiate it if necessary? (The prolonged execution time seems like a threat to me)
Do I have to shutdown and reinstantiate the taskExecutor if the submitted task fails to complete?
1) Should I check if my taskExecutor object is able to schedule a task before the submit call, and reinstantiate it if necessary?
2) Do I have to shutdown and reinstantiate the taskExecutor if the submitted task fails to complete?
For both the question no need
public static ExecutorService newFixedThreadPool(int nThreads)
Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue. At any point, at most nThreads threads will be active processing tasks. If additional tasks are submitted when all threads are active, they will wait in the queue until a thread is available. If any thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks. The threads in the pool will exist until it is explicitly shutdown.
Using #Scheduling to run method at #Scheduled(fixedRate = 10000) and set up #Scheduling threading by implementing SchedulingConfigurer
#Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
if I used Thread.sleep or Lock , no other thread is created by Executor unless Thread.sleep wake up or lock is cleared.
Can someone explain internal working if i have 10 pool size they 10 threads should be created at rate of 10000 millisec.
Basically such behavior comes from ScheduledExecutorService implementation which is used internally by spring. If you will run this code you will notice the same behavior:
public static void main(String[] args) throws Exception {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
executor.schedule(() -> {
System.out.println("Running task in thread " + Thread.currentThread().getId());
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
System.out.println("interrupted while sleeping");
}
}, 1000, TimeUnit.MILLISECONDS);
Thread.sleep(10000);
executor.shutdownNow();
}
When you submit task to scheduled thread pool it is wrapped with RunnableScheduledFuture which is passed to delayedExecute method. This method adds the task to the tasks queue and starts new worker if current number of workers is less than corePoolSize. Worker tries to get a task from the queue and process it invoking run method. There is a dedicated DelayedWorkQueue implementation which returns tasks only if they are ready for execution. Here is how run method of RunnableScheduledFuture looks like:
/**
* Overrides FutureTask version so as to reset/requeue if periodic.
*/
public void run() {
boolean periodic = isPeriodic();
if (!canRunInCurrentRunState(periodic))
cancel(false);
else if (!periodic)
ScheduledFutureTask.super.run();
else if (ScheduledFutureTask.super.runAndReset()) {
setNextRunTime();
reExecutePeriodic(outerTask);
}
}
As you can see it invokes actual task logic in runAndReset, calculates the next running time and submits the same updated task to the queue again (reExecutePeriodic is almost the same as schedule). There is only a single periodic task for all executions which is resubmitted again and again with updated time after the previous execution is finished. So such thread pool runs only a single instance of each task type in any given moment and scales only for different type of tasks.
If you are interesting in how spring schedules tasks take a look at ScheduledTaskRegistrar class and particularly at scheduleFixedDelayTask method.
In the case that you use threadpool:
By default you going to have 10 threads in your pool(already initialized). The first time that #scheduled is executed, this function is going to execute in a thread from your pool (now remaining 9 threads), if the function yet finished and #scheduled is executed again, your function going to executed in other thread from you your pool, so now you have 8 thread remaining in your pool. (8 idle, 2 running threads)
If you aren`t use threadpool only one thread is used.
spring documentation:
If you do not provide a 'pool-size' attribute, the default thread pool
will only have a single thread. There are no other configuration
options for the scheduler.
https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/html/scheduling.html
Difference between:
A)
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<> periodicTask = executorService.scheduleAtFixedRate(() -> {
try {
doSomething();
} catch (Exception e) {
log.error("Unhandled exception caught whilst doing minutely run", e);
}
}, initialDelay, PERIOD, TimeUnit.MILLISECONDS);
// In a shutdown hook:
periodicTask.cancel(true);
Does that cancel all the running tasks? Does it kill the ExecutorService?
B) The other way would be:
executorService.shutdown();
executorService.awaitTermination(....);
What's the difference?
Also how do I know how many tasks in the future the executorservice schedules?
Once I get the shut down signal I just want to run my scheduled task around 2 - 3 more times until I reach a certain condition. After that I want to kill it.
periodicTask.cancel(true);
The cancel method only stops the unstarted jobs and interrupts the running thread which then must return from the run() method.
executorService.shutdown();
The shutdown() method prevents clients sending more work to the executor service. This means all the existing tasks will run to completion.
executorService.awaitTermination(....);
This helps the application shut down gracefully. i.e. The executor service takes no more work and waits till all the executing jobs finish and then shuts-down.
I need to perform some data collection periodically, for that I want to create a task which requests some data from different servers. Some servers will take more time to process the request and return the response than others.
That's why I want to create a task for each server and execute the tasks async. If i'm using ScheduledExecutorService in the following way will each task execute in its own thread or all the tasks will be executed in the same thread?
What happens if a task is throwing an exception all the other scheduled tasks will fail?
this.scheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
return new Thread(r, "collectionThread");
}
});
for (String url:urls){
this.scheduler.scheduleWithFixedDelay(new CollectorTask(url),
startupDelaySeconds,
scheduleRateSeconds,
TimeUnit.SECONDS);
}
You're using a single-threaded executor service, so all tasks are being executed sequentially. If any of them throws an exception, all next tasks executions are cancelled.
You could use
Executors.newScheduledThreadPool(4) // 4 is the max number of parallel jobs
... to allow parallel execution and wrap a body of a submitted job into
try {
...
} catch(Exception e){
logger.warn("exception during task execution", e);
}
to log errors without propagating them.
Minor delays (several milliseconds) are possible and depend on the OS, tasks will never execute earlier than their scheduled time. Task's execution can be delayed due to previous long runs or lack of free threads, but the following executions will be run by the original schedule: initialDelay + n * period.
Yes, what you do is create two thread executors. The first is a scheduled executor which takes a runnable that is meant to start your actual runnable. All this runnable does it create an instance of your task runnable and submit it to the real executor. That executor should just be a normal thread pool that will handle the tasks.
private final ScheduledExecutorService scheduledExecutor = Executors
.newSingleThreadScheduledExecutor();
private final ExecutorService executor = Executors.newCachedThreadPool();
private class SubmitTaskRunnable implements Runnable {
#Override
public void run() {
executor.execute(new TaskRunnable());
}
}
Schedule the SubmitTaskRunnable on your scheduled executor because that one will not throw any exceptions. Let your actual task run inside a cached executor will allow multiple tasks to run concurrently even if the previous ones have not finished.