Question

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);
}
Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top