I’m using a ScheduledThreadPoolExecutor to schedule a task every millisecond. As far as I understand, ScheduledThreadPoolExecutor uses an unbounded queue internally and appends tasks when none of the threads is available to execute it.
As a result I would have assumed the following: if I have an executor with a single thread and the task that is periodically run takes longer than the frequency with which it is scheduled then the queue size increases continuously. Somehow this does not seem to be correct though for my following minimal code example:
import java.util.concurrent.{ScheduledThreadPoolExecutor, TimeUnit}
object MinimalExample {
val numberOfThreads = 1
val executor = new ScheduledThreadPoolExecutor(numberOfThreads)
def execute(): Unit = {
val thread = new TestThread(executor)
val initialDelay = 0
val interval = 1
executor.scheduleAtFixedRate(thread, initialDelay, interval, TimeUnit.MILLISECONDS)
}
def main(args: Array[String]): Unit = {
execute()
}
}
class TestThread(executor: ScheduledThreadPoolExecutor) extends Runnable {
override def run(): Unit = {
Thread.sleep(2000)
println("just slept 2 seconds")
println(s"queue size: ${executor.getQueue().size()}")
}
}
It always prints 0 for the size of the queue. How is that possible if the task takes more than 2 seconds and is scheduled every millisecond? Am I missing something?
While a periodic task is being executed, it is removed (take()-n or poll()-ed) from the internal queue. It is re-added later when the task is successfully finished. (Or not if it throws an exception.) This applies to both scheduleWithFixedDelay and scheduleAtFixedRate. getQueue returns the internal queue of tasks waiting for execution. This queue also contains delayed tasks that are waiting for their delay to expire, but not tasks that are currently being executed. (Use getActiveCount to query that.)
Quoting the javadoc for scheduleAtFixedRate:
If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
This is done by re-adding the periodic task to the queue only after it's execution. The task itself is not present in the queue during it's execution and will never be present in it multiple times.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With