Question about ScheduledExecutorService.shceduleAtFixedRate - I schedule taskA to run every 500 millis, which blocks for 1000 millis. Now subsequent executions aren't gonna wait the extra 500 millis, but rather commence immediately after the previous one.
taskA acquires an intrinsic lock, which is also (attempted) acquired by a different thread. Since intrinsic locks have no fairness guarantees this thread is running a risk of starvation, so here's my question: Is there a good/clean way to avoid this risk? E.g. schedule the task to run every 1500 millis (doesn't sound very waterproof)? Or do we expect the lock acquisition to exhibit a kind of "amortized fairness"?
Yes, you can use scheduleWithFixedDelay:
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next. If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor.
So the delay you give is the time between end of last end start of next - ie no overlap between runs.
Related
In a worker verticle using vertx.setPeriodic to setup a timer, let's say the delay is 100ms but the handler cost 5000ms to finish, what will happen if the app running for a long time. Will it cause a memory leak problem ? If it does, how to void the memory problem ?
vertx.setPeriodic(100, timer -> {
vertx.executeBlocking(future -> {
// here are some blocking code may cause 5000ms to complete the future.
}, res -> {
});
})
Eventually yes it will cause memory issues because,
Since code inside periodic is executing inside executeBlocking it will be executing on worker pool configured (which has fix size) and Since order parameter is not specified, each executeBlocking call will be executed serially (i.e. one after another).
Since periodic is running on event loop thread, it will never wait and will continue to trigger after fix period passed to it(100 ms in your case).
hence, calls to code inside periodic will be executed serially and will get stacked up. Once worker pool exhausts, calls on executeBlocking will go into the wait state.
Few choices to handle this can be (One of or a combination of),
Have separate Worker verticle for periodic.
Define separate worker pool by name dedicated for periodic.
Fine-tune the periodic frequency as per average time required to run periodic job.
If you don’t care about ordering you can call executeBlocking specifying false as the argument to ordered. In this case, any executeBlocking may be executed in parallel on the worker pool.
I know that I must use this instead of java.util.Timer because of various reasons. So, to study this I was looking at the docs and I have a few questions:
How does scheduleWithFixedDelay() work ? My understanding is this: It first executes a task after a given delay. Once the task is done, it waits for the specified time and then executes the task again.
What happens when I submit a task to scheduleAtFixedRate() that takes a lot more time to execute than the specified delay ? Like I want the task to execute every 5 seconds but it takes 10 seconds to complete. My understanding is that the task will be held in a queue and will be executed once a core thread is available
Here is my understanding of how scheduleWithFixedDelay() and scheduleAtFixedRate() differ: scheduleWithFixedDelay() waits for the task to finish executing, waits for the specified time and then fires the task again where as scheduleAtFixedRate will just keep firing the task without caring if it has completed or not. Correct?
Correct.
Not quite. If a fixed-rate task takes longer than its period, it will run again immediately upon completion, but the next run is not waiting for a thread. See below.
A fixed-rate task does care whether its previous run has completed, just like a fixed-delay task. Per the documentation, "If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute."
Think of it this way:
For a fixed-delay task, you specify a period which will be the exact amount of time between runs. The actual duration of the task has no effect on the delay.
For a fixed-rate task, you specify a period which will be the maximum amount of time between runs. If the actual duration of the task is longer than the period, the rate is reduced, and there is effectively no delay.
The docs for ScheduledThreadPoolExecutor says that -
Tasks scheduled for exactly the same execution time are enabled in first-in-first-out (FIFO) order of submission.
Does this mean that the tasks which SHOULD be done at the same time are never done at the same time. Instead they are executed in FIFO order ?
If that is true then which class do I use which is better than Timer and also does not have this FIFO problem ?
The way a ScheduledThreadPoolExecutor works is there is a single "scheduling" or master thread which checks for tasks to execute.
If it finds a task, it delegates it to a "worker" thread from the pool.
If multiple tasks are ready to be executed, they are "kicked off" one at a time, though once "kicked off", subsequent processing is concurrent, per Java's definition.
If you have two tasks that are both scheduled through the executor for the same time, the order in which they complete could vary from run to run and unless you put in specific controls such as locks, waits, etc... to handle this, it's up to java's thread scheduling (how java allots time to threads on a core) to determine how and when what gets processed. Please note that setting up such locks, waits, etc... is a deceptively complex task prone to race conditions leading to unexpected deadlocks, live locks, etc...
It depends on the size of your thread pool. If you schedule 1000 tasks to fire at midnight, and you only have 25 threads, then only 25 can be executed initially, while the rest must wait for available threads. FIFO here refers to the order in which the executor will hand tasks off to the execution threads.
Please note that the docs talk about "enabling" the tasks and that we are talking about a threadpool executor. :-)
That means the tasks will wait until the designated time, then they are treated as if put into a normal ThreadPoolExecutor. If there are enough threads available in the pool all these tasks will be run in parallel.
Only if you have more tasks becoming active than available threads in the pool some tasks will have to wait.
I have a question regarding the scheduleAtFixedRate() method on ScheduledExecutorService in Java 6.
[edit: the Javadoc for 1.6 is more complete than that for 1.5. See comment below]
Given that:
the ScheduledExecutorService is constructed with N = 1 thread in the pool
the fixed-rate is a period of T seconds
no initial delay
What happens in this case (times are not meant to be absolute, in the real-time sense):
at time T, the service kicks off a Runnable task, "task1"
at time 2T, task1 has not yet completed, and service is scheduled to fire
Is the service guaranteed to do any of the following?
(a) at 2T, kick off a Runnable task, "task2" (recall N = 1)
(b) block until task1 is finished
(c) skip this time and try again at 3T
(d) behavior is undefined
Or something else? Does the answer change if N > 1 ?
The answer is
(b) block until task1 is finished
and that is regardless of number of threads of the executor (task2 might even be not submitted).
The doc says:
If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
(BTW, since there's no intial delay, "task1" will kickoff right away as doc`ed:
executions will commence after initialDelay
).
From the documentation that you linked...
If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
I know one difference:
If we say thread.sleep(1000), that thread will sleep for 1000 milliseconds for sure, whereas with yield() there is no such guarantee. This is useful for thread scheduling, since the thread which calls yield() may very well selected immediately again for running.
What else?
Thread.sleep()
The current thread changes state from Running to Waiting/Blocked as shown in the diagram below.
Any other thread with reference to the thread currently sleeping (say t) can interrupt it calling t.interrupt()
the call to sleep has to be encapsulated to catch the checked exception of InterruptedException
After the time period for which the thread was set to sleep it goes to the Runnable state and might not run immediately! It has to wait for the Thread Scheduler to schedule it for its time slice.
Thread.yield()
Calling it may cause the Thread Scheduler to move the current thread from Running to Runnable state and execute another same priority thread which was in Runnable state. This transition of state takes place only if there is some other thread of same priority in Runnable state. Hence the no guarantee that the thread will stop execution as the criteria of another same priority thread might not be met.
.yield() is much based on the Thread Priorities concept. (All thread are assigned priorities and when a thread of higher priority is in Runnable state it ususally preempts / stops execution of lower priority threads depending on implementation of ThreadScheduler.)
Note:
both Thread.sleep() and Thread.yield() are static functions and affect the current thread executing it.
both the functions will not let go the synchronized locks they hold.
yield merely says: now is a good time to let another thread run and is a hint to the scheduler. sleep really does that: sleep at least the given time.
yield() pauses momentarily the current thread, allowing the Thread Scheduler to execute other threads with the same priority. If there are no other threads waiting or their priority is lower, the yielded thread returns to its execution at once.
sleep() forces the current thread to halt its execution for a defined slot of time. Other waiting threads will start executing by taking advantage of this pause, that is, following the Thread Scheduler policy - whose implementation is vendor dependent.
It's not "for sure" -- it could even take an hour for your thread to get another chance to run, depending on the operating system's thread scheduling algorithm, and the presence of higher-priority threads.
The only thing yield() does is say, "Okay, I'm kind of done, so feel free to end my time slice and continue executing something else." sleep, on the other hand, says "Wake me up in X milliseconds". sleep is used for waiting, the other one for giving others a chance to run. They're not alternatives.