I want to schedule an event to happen at a particular time, regardless of whether the computer suspends in the meanwhile. If computer is suspended when the event should have occurred, I want it to be scheduled immediately on resume.
I tried two ways: a thread with a sleep(), and a Swing Timer. Both these methods rely on a timed delay, and both suffer the same problem in that the delay countdown is suspended when the computer suspends, and continues only when the computer resumes, so the event occurs at (original delay + time suspended).
I then guessed that what I should be doing is to use a (util) Timer with a target Date, as this specifies a point in time, like so:
Date targetDate = new Date(System.currentTimeMillis() + (60 * 1000)); // in 1 min
Timer eventTimer = new Timer();
eventTimer.schedule(eventThread, targetDate);
Unfortunately this suffers in exactly the same way.
I did also look at the ScheduledExecutorService (although overkill for this application I thought) but it explicitly uses delays, so I assumed it would suffer the same problem.
Is what I want to do possible?
the delay countdown is suspended
No, this is not really what happens. Otherwise it would mean the system time would be wrong on resume!
Is what I want to do possible?
Here is a solution:
have one task handle all the scheduling, which runs, say, every second;
in a task to be executed, record the time, make the class of your task Comparable against the expected execution time;
put all these tasks in a PriorityQueue (or even a PriorityBlockingQueue);
when the scheduling task wakes up, peek the tasks; if the expected execution time is less than, or equal, to the current time, dequeue it and execute it; repeat until the peeked task has an expected execution time greater than the current time.
This will not make for "immediate execution upon resume", but close to.
Things are even weirder. I have a program that refreshes data on an hourly basis, using java.util.Timer and a suitable TimerTask. With openSuse up to version 13.1 that program worked as required - when due to a suspend the real time exceeded the cycle, the task was called "immediately" after the resume.
Running the same program with the same jvm (1.8.0_40-b10) and the same Linux kernel (3.14.24), but with openSuse 13.2, the task is not called on resume but only after the period has expired in wake mode.
I have solved this problem by calling the task via a function key if the current time exceeds the scheduled time and resynchronizing the task if necessary. That's a nuisance but acceptable because the resume is anyway done via a key stroke.
Related
I have a java process which could either complete sooner or take longer time based on the volume of data its processing. However I need a way to capture the elapsed time after certain time continuously and need to log an alert message concurrently without interrupting the main process. I have explored Future option with ExecutorService but it would terminate the process after the set timeout and raises Timeout exception. Please suggest if you have any solution to achieve this requirement.
just some hints:
you need to have 2 separate threads: one for main logic and one for checking the progress
the thread that checks the progress should be able to know if the main thread has finished or not (the simplest solution volatile boolean flag)
the thread that checks the progress can be invoked by timer with some period
I am using SchedulerExecuterService to execute a task after specified delay and at given intervals.
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(taskThread,60 ,120 ,TimeUnit.SECONDS);
What happening is first time taskThread is not starting after delay of 60 sec, it is started after delay of more than 60 secs. Whereas the next executions started at correct intervals of 120 secs(not exactly 120 secs but there is a very minute delay which can be ignored).
My query is why the first execution is delayed for more than 60 secs? Since the task is executed by a thread, Does the start up time depends on the thread priority?
How can I make it run at exact delay of 60 secs? What about Quartz library? Will this library solve my purpose(run the job at specific time without any delay)?
Thanks in advance.
Startup of a job depends on the scheduled time and the amount of threads available - if there are none available, it can be delayed. However, further executions will start at a scheduled time (delay + n * period) - which is takes place in your case.
Start will happen approximately at a scheduled time, I doubt there are real-time guarantees for this, it depends on the underlying OS. You could try changing a thread priority for a thread in this thread pool. This could help, but it won't give you a guarantee that it would work out in different environment.
You could also make sure you run a single task for a fixed thread pool of a single thread you use. Or try increasing the thread amount.
T.b.h. the delay you are seeing is unlikely to be ScheduledExecutorService's fault. Starting a thread won't take a second unless your machine is ridiculously overloaded, and I think the thread will get initialised up-front anyways if you use a fixed size thread pool.
I'm guessing it's the initialisation of your own tasks. I don't know what you are doing in your task, but getting the resource ready (starting DB connection pools) etc. can amount to significant time.
If you want you can test with a trivial task (like writing "hello" on the console) to see. And then you can measure each part of your task to see what's taking long. Once you have that you can think of ways to "warm" your system to prevent the delay.
In Timer.schedule(TimerTask task, long delay), it says it will throw if delay is negative, but doesn't say anything about if delay is zero. What will happen? I tried on openjdk and it ran instantly. Is this behavior specified somewhere else, or is it undefined (e.g it means infinite on other implementations, or some implementations will do infinite sometimes and instant sometimes)?
From the Java SE7 documentation:
If delay is less than or equal to zero, the timer fires as soon as it is started
So the result you got is the expected behavior.
I believe a Timer in java is a Thread with a task queue. Items are ordered in the task queue by when they are supposed to fire. Tasks with a delay of 0 are supposed to fire immediately and thus go to top of queue. I believe the behavior you are seeing is expected and should be consistent cross platform and across different jdks
I need to execute an action after a specific amount of time (for example 30 minutes after the app started up, if the app is still up).
What are my options and will it necessary means there's going to be one thread "lost" waiting for the 30 minutes to pass by?
Ideally, at program startup, I'd like to do something like the following (simplified on purpose) and then don't have to think about it anymore:
doIfStillUp( 30, new Runnable() {
....
});
So how should I go about implementing doIfStillUp(...)?
Should I use a TimerTask? The Executor framework?
Most importantly (it's for understanding purpose): does this mean there's going to be one thread lost idling for basically nothing during 30 minutes?
If there's going to be one thread "doing nothing", is this an issue? What if there are 10 000 threads (I'm being facetious here) "doing nothing"?
Note that I'm trying to understand the "big picture", not to solve a particular problem.
The Executor framework is a reasonable choice.
There's a schedule method that just takes a runnable and a delay time.
schedule(Runnable command,
long delay,
TimeUnit unit)
That's pretty straightforward. There won't necessarily be a thread blocked waiting on your task. You could use a ScheduledThreadPoolExecutor, as linked above that keeps X threads ready to run scheduled tasks.
You can imagine a data structure that holds the time at which a task should be run. A single thread can watch or set up these delays and can potentially watch thousands of them in a single thread. When the first time expires it'll run the task. Potentially using its own thread, potentially using 1 of X in the thread pool. When a new task is added or an existing task is finished it'll wait for the earliest time to arrive and then start the whole process again.
You should use a Timer. Its javadoc answers all your questions.
One thread is used for every timer, but the timer executes several tasks, sequentially. The timer tasks should be very short. If they aren't, consider using several timers.
Of course, the timer thread will be idle if it doesn't have any task to execute. An idle thread doesn't consume anything (or nearly anything), so I wouldn't worry about it. Anyway, you don't have many choices. 10000 threads doing nothing would of course be an issue, but that would mean that you instantiated one timer per task, which is wrong.
You can schedule task on java.util.Timer. For all timer tasks single timer thread will be created by java.util.Timer.
The builtin java timer is the straight away solution: http://download.oracle.com/javase/1,5.0/docs/api/java/util/Timer.html#schedule(java.util.TimerTask, long)
I'm using Timer as an process interrupt mechanism. The flow of logic is as follows:
T0: create new timer at T0 and schedule a new timer task to execute at T2 (1 second task delay, task is very simple - sets a flag variable)
T1: in the main calling thread, sleep for 5 seconds
T2: in the timer thread, task executes
T5: sleep finishes
T6: cancel timer and any scheduled tasks
The code works perfectly on my Windows and Ubuntu dev environment. But when I run the same code on my SLES 10 build server, logging indicates this execution order:
T0: timer and timer tasks are created to execute at T2
T1: main thread sleeps for 5 seconds
T5: main thread wakes up
T6: timer cancels
T7: task executes
Could anyone offer an explanation as to why this occurs? Thanks very much.
Hm. I'm surprised that you see that much difference (in seconds?), but I guess it is possible that you see different order of execution from machine to machine, jvm to jvm etc. Especially, when the JIT is compiling your code for the first time, I tend to see delay (compared to subsequent execution of same code) in the order of 100-300ms in my code for example, so maybe it's more dramatic in your code?
Not sure what you mean with "process interrupt mechanism". Do you mean that the timer task interrupts some thread?
Anyways, what I can suggest now is to use System.nanoTime() instead. (Although I don't think it will explain anything, Use of System.currentTimeMillis() is discouraged in serious measurements). Addition of -server to your JAVA_OPTS is generally advised so that you see the behavior when the code is optimized by JIT. It is also highly advisable to run your code multiple times and take statistics.
If I were you, I'll do these small things first, then debug using synchronizers like CyclicBarrier, CountdownLatch and see where exactly the delay is coming.
What are the "background noise" (degree of activity) in the SLES? Maybe the OS is very very busy or something?
What is the task's nature? Is it anything network/IO related?
It turned out it was a timestamp issue. Using new Date().getTime instead of System.currentTimeMillis yielded the expected order of execution timestamps.
Thanks for all the good ideas.
You should consider firing an event when the tasks are complete. That ensures execution order.