Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Working of newSingleThreadScheduledExecutor, if thread already busy

Tags:

java

android

My requirement is to make a service which keeps on checking a queue after specific interval & process the elements in queue.

For scheduling task after 10 seconds, I'm using:

ScheduledExecutorService schd = Executors.newSingleThreadScheduledExecutor();
schd.scheduleAtFixedRate(readQueueRunnable, 10, 10, TimeUnit.SECONDS);

My question is suppose first time, in queue there are many elements and my single thread starts processing the queue.

Even after 10 seconds my first thread is still executing it.

So when after 10 seconds, runnable is called again, will it stop the previous executing thread and start the new one. Or, it will check if thread is already running & if it is running then it will skip going inside Runnable in that case.

like image 988
reiley Avatar asked Jan 29 '14 16:01

reiley


1 Answers

newSingleThreadScheduledExecutor(); creates an executor with a single thread that will never do anything in parallel to itself. A single thread can't execute more than 1 thing at a time.

If your task takes longer than the desired rate of 10 seconds, it will, upon completion put itself back into the task queue cleared for immediate execution because the target time is already in the past.

A task will not be executed earlier than specified but it can always execute later.

The executor will also try to catch up to the specified rate. If it needs to have executed the task at 10 seconds, 20 seconds and 30 seconds after calling scheduleAtFixedRate it will run them back to back if it was busy until then.

A repeating task that consistently takes longer than the desired rate will effectively slow down the rate and never catch up.

If your tasks on average take less then the rate you'll have exactly as many executions of the task as the rate dictates.

So when after 10 seconds, runnable is called again, will it stop the previous executing thread and start the new one.

Executors re-use their thread(s) and they execute all Runnables you give them in sequence inside their thread(s). Executors also will not attempt to stop or interrupt a running task just because it takes too long.

Or, it will check if thread is already running & if it is running then it will skip going inside Runnable in that case.

No. You can calculate ahead of time when fixed rate task execution time is supposed to be and the executor will attempt to meet that goal. If a target time is already in the past it will simply run as soon as possible.

The documentation explains it like

If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.

The "not concurrently" part is meant for executors that have multiple threads. Not relevant here since that can't happen.


If you want that there is always a 10 second delay between tasks, use scheduleWithFixedDelay

With scheduleAtFixedRate when some executions take longer than the period you can see back to back execution of delayed tasks which is often undesired.

Example: execution the first time takes 25 seconds, each subsequent execution only takes 1 second. You'll end up with:

  • at 0s - 1st execution on time
  • at 25s - 2nd meant to run at 10s
  • at 26s - 3rd meant to run at 20s
    • (3 seconds pause)
  • at 30s - 4th on time again

If you use scheduleWithFixedDelay and set the delay to 10s you would end up with

  • at 0s - 1st for 25s
    • (10 seconds pause)
  • at 35s - 2nd for 1s
    • (10 seconds pause)
  • at 46s - 3rd for 1s
    • (10 seconds pause)
  • at 57s - 4th for 1s
like image 199
zapl Avatar answered Oct 28 '22 05:10

zapl