I am using Java executorservice to create a timeout effect in one of my apps. After an elapsed time, they executor service begins and logs the user out of their session. But on an Android device when the device goes to sleep the executor thread is suspended. After the device awakes the thread is unsuspended. I would like the change the clock the executor is using so that it continues counting even after the device goes to deep sleep. Is there no way I can over ride which clock is being used (I realize I can swap out the entire implementation and use alarmmanager but I'm looking to not alter existing code at this point so please do not try to offer other APIs).
My question is, there must be a system clock that keeps going despite the device being asleep, how can I let the executor scheduler use that clock instead of the one it's using now which respects the device going to deep sleep and pauses ticking?
My code I have currently is very simple and just looks like this:
myExecutorService.schedule(new EndUserSession(),
6L, TimeUnit.MINUTES);
this code above starts the EndUserSession() in 6 minutes. It works but I want to use another clock that does not respect time out of mobile device.
I have strong doubts that it's possible to influence scheduler service timing mechanisms.
You have another option to avoid problems caused by device sleep, like passing specific timestamp in constructor and scheduling a task at fixed rate. Example:
class EndSessionTask {
final long sessionExpirationTime;
volatile ScheduledFuture future;
public EndSessionTask(long ts) { sessionExpirationTime = ts; }
public void run() {
if (sessionExpirationTime < currentTs) return;
endSession();
future.cancel();
}
public void setFuture(ScheduledFuture f) { this.future = f; }
}
long endSessionTime = System.currentTimeMillis() + 6 * 60 * 1000;
EndSessionTask task = new EndSessionTask(endSessionTime);
ScheduledFuture future = executorService.scheduleAtFixedRate(task, 10L, 10L, SECONDS);
task.setFuture(future);
Related
I'm trying to execute a task at midnight after a fixed amount of days using ScheduleExecutorService. My method runs inside of my tomcat 8 and looks like this:
public void schedule (int aInterval)
{
String timezone = TimeZone.getDefault().getID();
ZoneId z = ZoneId.of(timezone);
ZonedDateTime now = ZonedDateTime.now( z );
LocalDate tomorrow = now.toLocalDate().plusDays(1);
ZonedDateTime tomorrowStart = tomorrow.atStartOfDay( z );
Duration duration = Duration.between( now , tomorrowStart );
long millisecondsUntilTomorrow = duration.toMillis();
long interval;
if (aInterval * 24 * 60 * 60 > Long.MAX_VALUE)
{
interval = Long.MAX_VALUE;
}
else
{
interval = aInterval * 24 * 60 * 60;
}
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
// allow the JVM to kill the scheduled task
thread.setDaemon(true);
return thread;
});
scheduler.scheduleAtFixedRate(new Runnable()
{
public void run() {
System.out.println(String.format("schedule::run() at %1$Td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS \n", System.currentTimeMillis() ) );
doTask();
}
},
delay,
interval,
TimeUnit.SECONDS);
}
Now when the method is first run it seems like is not executed as specifed by delay and interval. E.g. when i set delay=60 and interval=5 in my stacktrace it looks like this:
...
schedule::run() at 10.08.2017 17:57:09
schedule::run() at 10.08.2017 17:57:15
schedule::run() at 10.08.2017 17:57:21
schedule::run() at 10.08.2017 17:57:27
schedule::run() at 10.08.2017 17:57:27
schedule::run() at 10.08.2017 17:57:33
schedule::run() at 10.08.2017 17:57:33
schedule::run() at 10.08.2017 17:57:34
...
So the intervals somehow are becoming shorter and shorter over time. What is going on here? Is there a problem in my method?
Now when the method is first run it seems like is not executed as specified by delay and interval. E.g. when i set delay=60 and interval=5 in my stacktrace it looks like this...
I try to be very explicit with my time variables. In this case, you should be dealing with milliseconds so delayMillis, intervalMillis, aIntervalMillis, etc. should be in your code. If they are seconds then use delaySecs, etc. but you will need to multiple them by 1000 when you pass them to the scheduleAtFixedRate(...) method which is expecting millis.
So the intervals somehow are becoming shorter and shorter over time. What is going on here? Is there a problem in my method?
What's probably going on is that the task is trying to schedule it every 5 milliseconds so the random delays are just showing you how long your doTask() takes to run. If you want to set them to 60 and 5 seconds respectively then you should use 60000 and 5000 instead.
When i try that and my schedule() method is running i get a message from my eclipse (neon 3) saying tomcat is not responding and my tomcat is not shutting down properly.
Not sure about this but I suspect that your tomcat is waiting for your scheduled task to finish which is never will on its own. You could use a ThreadFactory and create a daemon thread instead which the JVM will not wait for when it shuts down. Note that if it is a daemon thread then it might get terminated right in the middle of running.
scheduler = Executors.newScheduledThreadPool(1, new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
// allow the JVM to kill the scheduled task
thread.setDaemon(true);
return thread;
}
});
Also, you should call scheduler.shutdown() on your thread-pool after you submit your fixed task. It will continue to run but no other jobs will be submitted. That's a good pattern.
How can I stop my execution task in a proper way?
The daemon thread mode about may be "proper" in your case but you can also cancel it. The scheduler.scheduleAtFixedRate(...) method returns a ScheduledFuture object that you can call cancel(...) on to stop it. Once your doTask() finishes it won't be scheduled again. You can also call cancel(true) on it to set the interrupt flag on the thread but your code is going to have to handle that specifically.
Of course you are going to need to detect that your JVM is shutting down so you can cancel your task. You could set a shutdown hook which is a bit of a hack. Maybe there is some way for tomcat to notify that it's coming down?
the intervals somehow are becoming shorter and shorter over time
We need to understand how ScheduledExecutorService:scheduleAtFixedRate is supposed to work. According to docs, https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html#scheduleAtFixedRate, we can conclude the following:
The time of each run is pre-determined.
This pre-calculated time may not tally when the previous run of the same task takes longer than point no 1. In such case, the
next run will happen immediately after the longer running previous run
has finished.
Same task can never run concurrently; even if the expected start time of the next run has exceeded. As mentioned by point no 2, the next run will wait till
the previous longer run finishes.
Now, coming to your case, you had expected to see your task getting run at equal intervals. But, instead the intervals between them are getting shorter with each run. This could be due to any previous run that took considerable longer time, piling up other run(s) which have exceeded their expected start time. Further piled up runs (doTask method) finish quickly. So, all the piled up runs are running at closer intervals. If you really want the task to run at equal intervals, you could instead use ScheduledExecutorService: scheduleWithFixedDelay
I have a pipeline of tasks to be done on files, each different type of task runs inside a different executor service. After initilizing each executor service I start the first task, this is guaranteed to not finish until finished processing all files, as it processes a folder either no more work is required or its submits a callable task to service2. So when the shutdown() call on first task is sucessful all files will now be being processed in task2 or a another task further down the pipleline, and so on. When we can shutdown the final service then we have finished.
Loader loader = Loader.getInstanceOf();
List<ExecutorService> services = new ArrayList<ExecutorService>();
ExecutorService es = Executors.newSingleThreadExecutor();
//Init Services
services.add(es);
services.add(task1.getService());
services.add(task2.getService());
services.add(task3.getService());
services.add(task4.getService());
//Start Loading Files
es.submit(loader);
int count = 0;
for (ExecutorService service : services)
{
service.shutdown();
count++;
//Now wait for all submitted tasks to complete, for upto one day per task
service.awaitTermination(10, TimeUnit.DAYS);
MainWindow.logger.severe("Shutdown Task:" + count);
}
public class AnalyserService
{
protected String threadGroup;
public AnalyserService(String threadGroup)
{
this.threadGroup=threadGroup;
}
protected ExecutorService executorService;
protected CompletionService completionService;
protected void initExecutorService()
{
int workerSize = Runtime.getRuntime().availableProcessors();
executorService
= Executors.newFixedThreadPool(workerSize, new SongKongThreadFactory(threadGroup));
}
public ExecutorService getService()
{
if (executorService == null || executorService.isShutdown())
{
initExecutorService();
}
return executorService;
}
}
So this is all working fine Except Ive got my cpu load logic incorrect. Every service uses a pool equal to the number of cpus the computer has. So if computer has 4 cpus and we have 5 services then we could have 20 threads all trying to work at the same time overloading the cpus. I think I should in this case only have 4 threads at a time.
If I limited each service to use one thread then Id only have 5 threads runningat same time, but this still isnt right because
Will no longer be right if have more services or more cpus
Is inefficient, as the pipleline kicks of most of the work will be done by task1 , if I limit it to one cpu it will be slower than neccessary, conversly later on most of the threads will be done by later tasks and task1 will have nothing to do.
I think what I need is for all tasks to share one executor service, and set its poolsize equal to the number of cput the computer has. But then how am I going to identify when the service has finished ?
Im using Java 7, so is there anything in new in Java 7 that may help, currently just using Java 5 concurrency features
The core of your problem is: "[...] overloading the cpus."
If this is the problem, just schedule the priority of your application correctly. By the way, you are more likely to increase IO load than to increase CPU load; a lot of different threads is actually a good thing :-)
However, your question is: " But then how am I going to identify when the service has finished ? "
Very simple answer: submit() instead of invokeAll() and check the isDone() method of the Future object you receive.
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ExecutorService.html#submit(java.util.concurrent.Callable)
I have a web application, I need to run a backgroung process which will hit a web-service, after getting the response it will wait for few seconds(say 30) then again hit the service. The response data can vary from very less to very large, so i dont want to call the processagain untill i am finished with processing of data. So, its a recursive call with a time delay. How i intend to do is:
Add a ContextListener to web app.
On contextIntialized() method , call invokeWebService() i.e. arbitary method to hit web service.
invokeWebService will look like:
invokeWebService()
{
//make request
//hit service
//get response
//process response
timeDelayInSeconds(30);
//recursive call
invokeWebService();
}
Pls. suggest whether I am doing it right. Or go with threads or schedulers. Pls. answer with sample codes.
You could use a ScheduledExecutorService, which is part of the standard JDK since 1.5:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable r = new Runnable() {
#Override
public void run() {
invokeWebService();
}
};
scheduler.scheduleAtFixedRate(r, 0, 30, TimeUnit.SECONDS);
It is not recursive but repeated. You have two choice here:
Use a Timer and a TimerTask with scheduleAtFixedRate
Use Quartz with a repeated schedule.
In quartz, you can create a repeated schedule with this code:
TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(30))
.build()
From what I am getting, waiting sort of implies hanging, which I do not really think is a good idea. I would recommend you use something such as Quartz and run your method at whatever interval you wish.
Quartz is a full-featured, open source job scheduling service that can
be integrated with, or used along side virtually any Java EE or Java
SE application
Tutorials can be accessed here.
As stated in here you can do something like so:
JobDetail existingJobDetail = sched.getJobDetail(jobName, jobGroup);
if (existingJobDetail != null) {
List<JobExecutionContext> currentlyExecutingJobs = (List<JobExecutionContext>) sched.getCurrentlyExecutingJobs();
for (JobExecutionContext jec : currentlyExecutingJobs) {
if(existingJobDetail.equals(jec.getJobDetail())) {
//String message = jobName + " is already running.";
//log.info(message);
//throw new JobExecutionException(message,false);
}
}
//sched.deleteJob(jobName, jobGroup); if you want to delete the scheduled but not-currently-running job
}
This question already has an answer here:
Spawning threads in a JSF managed bean for scheduled tasks using a timer
(1 answer)
Closed 7 years ago.
I am developing a web application where I need to run a thread for 60 seconds which needs to check for response coming from a webservice. If the response arrives within 60 seconds I will forward to success othewise I will forward to a time out page after 60 seconds. I am using JSF 2.0?
I have thought of using the Timer but not sure whenther I can run the timer for sprcefic amount of time only.
Is there any smart solution for this ??
Yes, youre able to create a timer which expires after a certain amount of time. See this link http://docs.oracle.com/javaee/1.4/api/javax/ejb/TimerService.html.
Java < vers. 6
Create Session- or MessageDriven-Bean
Inject TimerService
#Ressource
TimerService ts;
Create Timer
...
// create Timer which starts after 10s every 10s
Timer timer = ts.createTimer(10000, 10000, "Test-Timer");
...
Important: Timer Interval has to be >7sec, see Java Specs
Create Method to be executed when timer fires
#Timeout //marks Method to be executed by Timer
public void timerFired(Timer timer) {
// your code here
}
Java > vers. 6
Much comfortable with the #Schedule-Annotation
#Schedule(second="*/45", minute="*", hour="*", persistent="false")
public void scheduler() {
// your code here
}
The above code implements a timer which gets fired every 45s of every minute of every hour.
Have a look at wikipedia for more information about cron syntax.
Both methods implement the Serializable-Interface, so they are both thread-safe.
if you would like to extend this rudimental functionality you should take a look at Quartz.
Hope this helped! Have Fun!
Do absolutely not use Timer for this! It's funny for one-time-run desktop applications, but it has severe potential problems when used in a lifetime long running Java EE web application.
Rather use the executors from the java.util.concurrent package. Here's a kickoff example:
ExecutorService executor = Executors.newSingleThreadExecutor(); // An application wide thread pool executor is better.
Callable<InputStream> task = new Callable<InputStream>() {
#Override
public InputStream call() throws Exception {
// Do here your webservice call job.
return new URL("http://stackoverflow.com").openStream();
}
};
try {
InputStream input = executor.invokeAny(Arrays.asList(task), 60, TimeUnit.SECONDS);
// Successful! Forward to success page here.
} catch (TimeoutException e) {
// Timeout occurred. Forward to timeout page here.
}
It sounds like you should just sit in a loop for 60 seconds and sleep for a second between checks. Once 60 seconds has passed or the request came in let the code continue and forward the user to the appropriate page.
This is the simplest way. You could also use an ajax polling system which would be more user friendly because you can update the user interface with a countdown.
long startTime = System.currentTimeMillis();
boolean success = false;
while (System.currentTimeMillis() < startTime + 60000) {
// do check
success = checkSucceeds();
if (success) break;
try {
Thread.sleep(1000);
} catch (InterruptedException interruptedException) {
// ignore
}
}
if (success)
// forward to success page
;
else
// forward to error page
;
I'm developing an application that should execute some task periodically (10 seconds) in the background. For this I use Service and Timer. Actual jobs to be done in timer are:
1) collecting data from the phone (using ContentResolver) into the SQLite database,
2) sending this data to remote server synchronously using HttpPost method.
The problem is next: after some iterations (ammount of these iterations changes every execution of the app) timer changes its period and start to perform all the tasks with 1-3 seconds (sometimes up to 9, but it always lower than 10 secs) delay, which is way too fast in my case and I can't find the reason.
Has anyone faced similar behavior before?
I've tried to use different threads for uploading and collecting inside the timer task, but it didn't solve the problem.
Here's my code snippets:
public class DataForward extends Service{
private Context con = getBaseContext();
private Timer timer = new Timer();
<...>
#Override
public void onStart(Intent intent, int startId) {
timer.schedule(new TimerTask(){
#Override
public void run() {
try {
updateData();
NetworkManager network = new NetworkManager(con);
if(network.isConnectedToTheInternet())
uploadData();
} catch (Exception e) {
e.printStackTrace();
}
}}, 0, 10000);
}
}
<...>
}
Or maybe there's another way to do this without actual Timer?
Any Ideas?
The reason could be, since you told its running on a service, its so possible that your
backgroundTask(Service) may get killed when android OS finds its going low on RAM inorder to keep its
foreGround Applications running.. And again when it gets Free Ram it Restarts the Service Again, so
it may be restarting timer again and again.
for more Read THis ..SERVICE
First execution of your time is 0 millis and subsequent execution is after 10 millis.But android os may stop your service for internal task management.So,again when your service start s after some time then it reset timer again.So,it will execute your task immediately.thats the reason of your problem.
So you can set a time minimum time for your first execution or can use repeating Alarm.