java ScheduledExecutorService task stops after several executions - java

I have a problem, I am trying to execute a Task in ScheduledExecutorService, and I am executing the task with the command:
updateTagDataHandle = scheduler.scheduleWithFixedDelay(updateTagDataRunnable, 500, 500, TimeUnit.MILLISECONDS);
and after several success runs it stops. the task itself takes a few seconds I checked with println that it go to the end of the task with no errors, and I print any exception and didnt see an exception in the end. I need it to continue run infinite number of times.
any help would be appreciated
edit
my code for initializing the task scheduler was:
scheduler = Executors.newScheduledThreadPool(1);
so the corePoolSize = 1 so there only one thread alive and the task share this on thread. but setting the threadPool to be more than one is not helping and still there seems to be only one thread active.
same question here:
Executors Factory method newScheduledThreadPool always returns the same Thread pool
and here:
Why doesn't ScheduledExecutorService spawn threads as needed?
any help would be appreciated
edit:
didnt find a solution so used the scheduler custom thread creation :
scheduler = Executors.newScheduledThreadPool(7, new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
return new Thread(r);
}
});

Try changing the initial delay to 1000 milliseconds.
I was trying the same code in my android app and this solved the problem.

Related

Spring Java #Scheduling configuration

Using #Scheduling to run method at #Scheduled(fixedRate = 10000) and set up #Scheduling threading by implementing SchedulingConfigurer
#Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
if I used Thread.sleep or Lock , no other thread is created by Executor unless Thread.sleep wake up or lock is cleared.
Can someone explain internal working if i have 10 pool size they 10 threads should be created at rate of 10000 millisec.
Basically such behavior comes from ScheduledExecutorService implementation which is used internally by spring. If you will run this code you will notice the same behavior:
public static void main(String[] args) throws Exception {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
executor.schedule(() -> {
System.out.println("Running task in thread " + Thread.currentThread().getId());
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
System.out.println("interrupted while sleeping");
}
}, 1000, TimeUnit.MILLISECONDS);
Thread.sleep(10000);
executor.shutdownNow();
}
When you submit task to scheduled thread pool it is wrapped with RunnableScheduledFuture which is passed to delayedExecute method. This method adds the task to the tasks queue and starts new worker if current number of workers is less than corePoolSize. Worker tries to get a task from the queue and process it invoking run method. There is a dedicated DelayedWorkQueue implementation which returns tasks only if they are ready for execution. Here is how run method of RunnableScheduledFuture looks like:
/**
* Overrides FutureTask version so as to reset/requeue if periodic.
*/
public void run() {
boolean periodic = isPeriodic();
if (!canRunInCurrentRunState(periodic))
cancel(false);
else if (!periodic)
ScheduledFutureTask.super.run();
else if (ScheduledFutureTask.super.runAndReset()) {
setNextRunTime();
reExecutePeriodic(outerTask);
}
}
As you can see it invokes actual task logic in runAndReset, calculates the next running time and submits the same updated task to the queue again (reExecutePeriodic is almost the same as schedule). There is only a single periodic task for all executions which is resubmitted again and again with updated time after the previous execution is finished. So such thread pool runs only a single instance of each task type in any given moment and scales only for different type of tasks.
If you are interesting in how spring schedules tasks take a look at ScheduledTaskRegistrar class and particularly at scheduleFixedDelayTask method.
In the case that you use threadpool:
By default you going to have 10 threads in your pool(already initialized). The first time that #scheduled is executed, this function is going to execute in a thread from your pool (now remaining 9 threads), if the function yet finished and #scheduled is executed again, your function going to executed in other thread from you your pool, so now you have 8 thread remaining in your pool. (8 idle, 2 running threads)
If you aren`t use threadpool only one thread is used.
spring documentation:
If you do not provide a 'pool-size' attribute, the default thread pool
will only have a single thread. There are no other configuration
options for the scheduler.
https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/html/scheduling.html

ScheduledExecutorService not behaving as expected

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

Rejected Execution Exception

I get this error in the log file while thread is running, i don't know where this error occurs since the threads didn't stop and process data with no issues and only my problem that this error appears multiple times in the log file
java.util.concurrent.RejectedExecutionException: Task
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask#419a9977
rejected from
java.util.concurrent.ScheduledThreadPoolExecutor#2522cdb9[Terminated,
pool size = 0, active threads = 0, queued tasks = 0, completed tasks =
2123929]
I did some research, i found that in some places i shutdown the task, but that did not happen at all.
Without looking at the code we can't really inform you more about the problem. If you look at the exception then it clearly states that the threads have been terminated and their active count is zero. It seems even after shutting down the executor you are trying to process more code using executors. Are you trying to add more task after the call executor.shutdown()
As per docs, New tasks submitted in method execute(Runnable) will be rejected when the Executor has been shut down, and also when the Executor uses finite bounds for both maximum threads and work queue capacity, and is saturated. In either case, the execute method invokes the RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor) method of its RejectedExecutionHandler.
Look at the doc here: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html
Old question, but I had the issue and the comment of #lambad saves my day. I had this piece of code:
ttlExecutorService.schedule(new Runnable() {
public void run() {
...
...
...
}
}, 1, TimeUnit.MINUTES);
ttlExecutorService.shutdown();
I removed the shutdown call and exception was no longer thrown

Eclipse : ScheduledExecutorService.scheduleWithFixedDelay does not remove on publish

I got weird problem.
I have a ScheduledExecutorService.scheduleWithFixedDelay which doesn't not "stop" when i click publish / stop-restart server .
When i republish, there will be 2 service running and the number of same service running depends on how many times I click publish.
This does not go away after I stop and start server.
I have to close eclipse and open to stop it and I notice this happen only after i edit the class that initialize the service.
I'm unable to paste the codes but is very simple.. just a Singleton and holds the service
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() { system.out("hello" }
}, 60 * 60, SECONDS);
I can't seems to find out the issue, can someone help me please.
You're supposed to shut down the scheduler when the application is undeployed. The easier way to do that is to declare an implement a ServletContextListener, and shut down the schedler in the contextDestroyed() method.
Executors.newScheduledThreadPool(1); creates a non-daemon worker thread and it prevents JVM from shutting down unless you shutdown scheduler explicitly
scheduler.shutdown();
alternatevely, you can do the following
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1,
new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(false);
return t;
}
});
in this case the worker thread will be a daemon and will not prevent the JVM from exiting when the program finishes

How to stop immediately a task which is started using an ExecutorService?

I have tried many different ways to immediately stop a task which is started using an ExecutorService, with no luck.
Future<Void> future = executorService.submit(new Callable<Void>(
public Void call () {
... do many other things here..
if(Thread.currentThread.isInterrupted()) {
return null;
}
... do many other things here..
if(Thread.currentThread.isInterrupted()) {
return null;
}
}
));
if(flag) { // may be true and directly cancel the task
future.cancel(true);
}
Sometimes I need to cancel the task immediately after it is started, you may be curious why I want to do this, well you may imagine a senario that a user accidentally hits the "Download" button to start a "Download Task" and he immediately wants to cancel the action because it was just an accidental click.
The problem is that after calling future.cancel(true), the task is not stopped and Thread.currentThread.isInterrupted() still returns false and I have no way to know the task was stopped from inside the call() method.
I am thinking of setting a flag like cancelled=true after calling future.cancel(true) and checking that flag constantly in the call() method, I think this is a hack and the code could be very ugly because the user can start many tasks at the same moment.
Is there a more elegant way of achieving what I want?
EDIT:
This really drives me mad. I have spent almost a day on this problem now. I will try to explain a little bit more for the problem I am facing.
I do the following to start 5 tasks, each task will start 5 threads to download a file. and then I stop all 5 tasks immediately. For all of the method calls below, i start a thread(ExecutorService.submit(task)) to make it asynchronous as you can tell from the suffixes of the methods.
int t1 = startTaskAysnc(task1);
int t2 = startTaskAysnc(task2);
int t3 = startTaskAysnc(task3);
int t4 = startTaskAysnc(task4);
int t5 = startTaskAysnc(task5);
int stopTaskAysnc(t1);
int stopTaskAysnc(t2);
int stopTaskAysnc(t3);
int stopTaskAysnc(t4);
int stopTaskAysnc(t5);
in startTaskAysnc(), I simply initiate a socket connection to remote server to get the size of the file(and this certainly is gonna take some time), after successfully getting the fileSize, I will start 5 threads to download different parts of the file. like the following(the code is simplified to make it more easy to follow):
public void startTaskAsync(DownloadTask task) {
Future<Void> future = executorService.submit(new Callable<Void>(
public Void call () {
// this is a synchronous call
int fileSize = getFileSize();
System.out.println(Thread.currentThread.isInterrupted());
....
Future<Void> futures = new Future<Void>[5];
for (int i = 0; i < futures.length; ++i) {
futures[i] = executorService.submit(new Callable<Void>(){...});
}
for (int i = 0; i < futures.length; ++i) {
futures[i].get(); // wait for it to complete
}
}
));
synchronized (mTaskMap) {
mTaskMap.put(task.getId(), future);
}
}
public void stopTaskAysnc(int taskId) {
executorService.execute(new Runnable(){
Future<Void> future = mTaskMap.get(taskId);
future.cancel(true);
});
}
I noticed a weird behavior that after I called stopTaskAsync() for all 5 tasks, there would always be at least one task that got stopped(i.e. Thread.currentThread.isInterrupted() return true), and the other 4 tasks kept running.
And I have tried your suggestions by setting an UncaughtExceptionHandler, but nothing comes out from that.
EDIT:
The problem was solved in this link: Can't stop a task which is started using ExecutorService
Well, the javadoc of Future.cancel(boolean) says that:
If the task has already started, then the mayInterruptIfRunning
parameter determines whether the thread executing this task should be
interrupted in an attempt to stop the task.
so it's quite certain that the thread that executes the task is interrupted. What could have happened is that one of the
... do many other things here..
is accidentally clearing the Thread's interrupted status without performing the desired
handling. If you'll put a breakpoint in Thread.interrupt() you might catch the criminal.
Another option I can think of is that the task terminates before capturing the interrupt, either because it's completed or thrown some uncaught exception. Call Future.get() to determine that. Anyway, as asdasd mentioned, it is a good practice to set an UncaughtExceptionHandler.
What you're doing is very dangerous: you're using a thread pool to execute tasks (which I'll call downloaders), and the same thread pool to execute tasks which
wait for the downloaders to finish (which I'll call controllers)
or ask the controllers to stop
This means that if the core number of threads is reached after the controller has started, the downloaders will be put in the queue of the thread pool, and the controller thread will never finish. Similarly, if the core number of threads is reached when you execute the cancelling task, this cancelling task will be put in the queue, and won't execute until some other task is finished.
You should probably use a thread pool for downloaders, another one for controllers, and the current thread to cancel the controllers.
I think you'll find solution here. The main point is that cancel method raises InterruptedException. Please check if your thread is still running after cancellation? Are you sure that you didn't try to interrupt finished thread? Are you sure that your thread didn't fail with any other Exception? Try to set up UncaughtExceptionHandler.

Categories