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.
Related
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
Look at the following piece of code:
public void pinger()
{
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
executor.scheduleAtFixedRate(runnable, start, rate, TimeUnit.SECONDS);
executor.shutdown();
}
Is there any use of writing the shutdown command in this case? Different clients would create their own runnable objects and invoke this function.
When you shutdown an executor, no new task will be accepted. Since you create a new one inside the pinger method every task has its own executor. A shutdown as you write will only free resource once the corrent task is terminated.
Some notes:
You should not create Executor for each client request.
Create Executor out side of client request and submit tasks to Executor
When you decide that you should not accept new tasks to Executor, then shutdown the executor. The right way of shutting down Executor is explained in below post:
How to forcefully shutdown java ExecutorService
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'm using a Java executor to divide and process a given task in parallel. There could be any number of tasks. They are all queued at the beginning and the master controller object simply waits for all of them to finish.
The problem I'm running into is how to determine when all tasks have been completed. Since one large task is only every queued at a single time (i.e. all currently queued tasks all belong to the same master task) I can use the getCompletedTaskCount() method to compare the number of completed tasks to the number of the number of tasks originally queued.
However, this requires that I constantly poll the executor for the number of completed tasks and in my opinion isn't that great of a solution.
while (pool.getCompletedTaskCount() - start_count < num_tasks)
{
try
{
Thread.sleep(30);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I thought about having a counter object which each task could increment, then if the count is equivalent to the number of expected tasks notify the master thread. Something like this (ignore the somewhat incomplete code like missing exception handlers and such):
Master thread:
counter_object.expected_count = num_tasks;
counter_object.count = 0;
queue_tasks();
synchronized(counter_object)
{
counter_object.wait();
}
// all tasks have finished
Worker tasks:
// ...do task
// task finished, update counter
synchronized(counter_object)
{
++counter_object.count;
if(counter_object.count == counter_object.expected_count)
{
// all tasks have finished, notify master thread
counter_object.notify();
}
}
This method also has the added benefit that I can use a single executor to run multiple master tasks since the counter object would be local to a given master.
Is there a better way to solve this problem? The number of tasks might very well be larger than the max number of threads the executor is allowed to create so I don't think a CyclicBarrier would work.
This sounds like a job of ExecutorService.invokeAll.
Collection<Callable> tasks = <get all sub tasks>;
executorService.invokeAll(tasks);
// Execution proceeds at the following line only once all "tasks" have been run
Alternatively (since you are likely dealing with Runnable instances and not Callable, you can use ExecutorService.submit(Runnable) and then wait for them to complete.
for (Runnable task:tasks) {
futures.add(executorService.submit(task));
}
for (Future<Void> result:futures) {
result.get();
}
Note: exception handling omitted