I am following up an interesting question on so, on usage of ScheduledThreadPoolExecutor for some repeating task.
Scheduling this object returns a ScheduledFuture object which one can use to cancel the next run of the task.
One thing to note here is the task itself is completely decoupled from the schedule--
ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1);
ScheduledFuture nextSchedule =
executor.schedule(task, 60000, TimeUnit.MILLISECONDS);
where-
SomeTask task = new SomeTask();
So the task itself is not aware of the schedule. Please enlighten if there is a way to get the task to cancel and create a new schedule for itself.
Thanks
There's no reason why the task cannot reference the ScheduledExecutorService and schedule itself to run again if required:
// (Need to make variable final *if* it is a local (method) variable.)
final ScheduledExecutorService execService = Executors.newSingleThreadScheduledExecutor();
// Create re-usable Callable. In cases where the Callable has state
// we may need to create a new instance each time depending on requirements.
Callable<Void> task = new Callable() {
public Void call() {
try {
doSomeProcessing();
} finally {
// Schedule same task to run again (even if processing fails).
execService.schedule(this, 1, TimeUnit.SECONDS);
}
}
}
Pass the executor to the task, so that it can make manipulations with it:
SomeTask task = new SomeTask(executor);
Related
I have a spring ThreadPoolTaskExecutor I submit some Callable tasks to this Executor.
Inside the Task I use a dynamic Map to set some values. And the Future of this Callable could be used to cancel this thread. Before starting this Callable I initialize some conditions, which are nullified or reverted back when the thread completes execution.
There might be a case when the Task has not started and it is cancelled. This means that the conditions have been initialized. But when a Thread that has not been started and is still with the pool, is cancelled I am unable to nullify my initializations as the call method is never called.
I read about it and if it was a Runnable thread then I could have handled it using the UncaughtExceptionHandler. Or if I was using future.get() to wait for the result then I could have handled the ExecutionException. Another solution is to override the afterExecute() but I could not find this in ThreadPoolTaskExecutor, also I am not very sure about this approach.
SO how do I handle it in this case?
The below code is called from a demon thread waiting on a BlockingQueue:
public void process(View view)
{
//getMapOfViewsAndFuture and getMapOfViewsPersistingLocks fetch the ConcurrentHashMaps
viewController.getMapOfViewsAndFuture().remove(view.getId());
viewController.getMapOfViewsPersistingLocks().put(view.getId(), new ReentrantLock());
Callable<WebResponse> calculatePI = (Callable<WebResponse>) mAppContext.getBean("piCalculator", view.getId()
,viewController.getMapOfViewsPersistingLocks().get(view.getId()), viewController.getMapOfViewsPrintingLocks().get(view.getId()));
Future<WebResponse> future = mExecutor.submit(calculatePI);
viewController.getMapOfViewsAndFuture().put(view.getId(), future);
}
The Callable (PICalculator) looks like this:
class PICalculator implements Callable<WebResponse>
{
#Override
public WebResponse call()
{
try
{
//business logic
mWebResponse = getResponse();
}
catch(Exception e)
{
//log the exceprtion
}
finally
{
//remove this entry from datasets
viewController.getMapOfViewsAndFuture().remove(mViewId);
viewController.getListOfCalculatingViews().remove((Integer)mViewId);
viewController.getMapOfViewsPersistingLocks().remove(mViewId);
}
return mWebResponse;
}
}
Nice question, With the Spring's ThreadPoolTaskExecutor, you can provide configuration for ThreadPoolExecutor(Java's inbuilt) like - corePoolSize, maxPoolSize etc., but you cannot set your custom ThreadPoolExecutor.
In this case, I will suggest you to use Spring's ConcurrentTaskExecutor,
Create an object of Java's ThreadPoolExecutor with the required configuration. See below constructor:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
Here you have to provide your own queue object.
Now you can override the afterExecute() method for cleanup the settings, as below:
ThreadPoolExecutor myExecutor = new ThreadPoolExecutor(3,5,5, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10)){
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r,t);
//Move your cleanup code here
//remove this entry from datasets
viewController.getMapOfViewsAndFuture().remove(mViewId);
viewController.getListOfCalculatingViews().remove((Integer)mViewId);
viewController.getMapOfViewsPersistingLocks().remove(mViewId);
System.out.println("do cleanup here");
}
};
Now set this executor in ConcurrentTaskExecutor object.
ConcurrentTaskExecutor.setConcurrentExecutor(myExecutor);
You can even pass your executor in the constructor of ConcurrentTaskExecutor.
ConcurrentTaskExecutor taskExecutor = new ConcurrentTaskExecutor(myExecutor);
Now your taskExecutor is ready to process your tasks, just call submit(callable) method to pass callables/runnables(tasks). Hope It may help you.
How to go about implementing a "fire and forget" behavior with java.util.concurrency? I tried:
ExecutorService executor = Executors.newSingleThreadExecutor();
public void push(Callable<Boolean> task) {
Future<Boolean> future = executor.submit(task);
future.get(timeout, timeoutUnit);
}
but the get() is blocking until completion. The push() caller is not interested in the result of the task.
Don't call get(). submit() is enough to start the Callable in a Thread. You can pass around the Future and call its get() when you are ready to get the result (if ever).
The Javadoc states
Submits a value-returning task for execution and returns a Future
representing the pending results of the task. The Future's get method
will return the task's result upon successful completion.
If you would like to immediately block waiting for a task, you can use
constructions of the form result = exec.submit(aCallable).get();
So just don't call get().
dont need the future object if you have to forget it i.e. dont care about the future of the thread. :)
ExecutorService executor = Executors.newSingleThreadExecutor();
public void push(Callable<Boolean> task) {
executor.submit(task);
}
or if you need to use future some time later than :-
ExecutorService executor = Executors.newSingleThreadExecutor();
public void push(Callable<Boolean> task) {
someCollection.add(executor.submit(task)); // use futures later
}
or just use execute from Executor and pass Runnable, if you dont intent to get the future at all.
ExecutorService executor = Executors.newSingleThreadExecutor();
public void push(Runnable task) {
executor.execute(task);
}
// execute will invoke default exceptional handler in case of exception, that can be lost in case if you dont get hold of futures in submit method.
Hey there i currently have a problem with my android app. I´m starting an extra thread via
implementing the Excecutor Interface:
class Flasher implements Executor {
Thread t;
public void execute(Runnable r) {
t = new Thread(r){
};
t.start();
}
}
I start my Runnable like this:
flasherThread.execute(flashRunnable);
but how can i stop it?
Ok, this is just the very basic threading 101, but let there be another example:
Old-school threading:
class MyTask implements Runnable {
public volatile boolean doTerminate;
public void run() {
while ( ! doTerminate ) {
// do some work, like:
on();
Thread.sleep(1000);
off();
Thread.sleep(1000);
}
}
}
then
MyTask task = new MyTask();
Thread thread = new Thread( task );
thread.start();
// let task run for a while...
task.doTerminate = true;
// wait for task/thread to terminate:
thread.join();
// task and thread finished executing
Edit:
Just stumbled upon this very informative Article about how to stop threads.
Not sure that implementing Executor is a good idea. I would rather use one of the executors Java provides. They allow you to control your Runnable instance via Future interface:
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<?> future = executorService.submit(flashRunnable);
...
future.cancel(true);
Also make sure you free resources that ExecutorService is consuming by calling executorService.shutdown() when your program does not need asynchronous execution anymore.
Instead of implementing your own Executor, you should look at ExecutorService. ExecutorService has a shutdown method which:
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
I would suggest to use the ExecutorService, along with the Furure object, which gives you control over the thread that is being created by the executor. Like the following example
ExecutorService executor = Executors.newSingleThreadExecutor();
Future future = executor.submit(runnabale);
try {
future.get(2, TimeUnit.SECONDS);
} catch (TimeoutException ex) {
Log.warn("Time out expired");
} finally {
if(!future.isDone()&&(!future.isCancelled()))
future.cancel(true);
executor.shutdownNow();
}
This code says that the runnable will be forced to terminate after 2 seconds. Of course, you can handle your Future ojbect as you wish and terminate it according to your requierements
I'm using 3rd Party concurrency library ported to 1.4 which can be downloaded from here
http://altair.cs.oswego.edu/pipermail/concurrency-interest/2004-September/001035.html
Executor executor = new PooledExecutor.....
FutureResult futureImage = new FutureResult();
Runnable command = futureImage.setter(new Callable() {
public Object call() { //doSomething }
});
executor.execute(command);
I need to cancel FutureResult or stop execution of current Runnable.
If I were using Future<P> from java 1.5, I would call cancel() method, but how can I do it here?
Implement Cancel yourself, for example by providing a cancelled variable which you check during execution of your future.
Is there a nice way to stop the repetition of task from within the task itself when running in a ScheduledExecutorService?
Lets say, I have the following task:
Future<?> f = scheduledExecutor.scheduleAtFixedRate(new Runnable() {
int count = 0;
public void run() {
System.out.println(count++);
if (count == 10) {
// ??? cancel self
}
}
}, 1, 1, TimeUnit.SECONDS);
From outside, it is easy to cancel via f.cancel(), but how can I stop the repetition at the specified place? (Passing the Future through an AtomicReference is not safe, because there is a potential window when the scheduleAtFixedRate returns f late and the variable is set late too, and the task itself might already run, seeing a null in the reference.)
When a repeating task throws an Exception or Error, it is placed in the Future and the task is not repeated again. You can throw a RuntimeException or Error of your choice.
Instead of using an anonymous inner class you can use a named class which can then have a property for the Future object you get from the Executor when you schedule a task.
abstract class FutureRunnable implements Runnable {
private Future<?> future;
/* Getter and Setter for future */
}
When you schedule a task you can then pass the Future to the Runnable.
FutureRunnable runnable = new FutureRunnable() {
public void run() {
if (/* abort condition */)
getFuture().cancel(false);
}
};
Future<?> future = executor.scheduleAtFixedRate(runnable, ...);
runnable.setFuture(future);
Maybe you will have to make sure, that the task is not executed before the Future has been set, because otherwise you will get a NullPointerException.
It seems like bad design for the Runnable to know anything about the executor it is running in, or to throw an error if reaching 10 is not an error state is a hack.
Can you do the loop to 10 outside of the scheduling and execution? This may require using a non-scheduling executor as you'd be scheduling them manually yourself.
Here is another way, that's even Thread safe;
final Future<?>[] f = {null};
f[0]= scheduledExecutor.scheduleAtFixedRate(new Runnable() {
int count = 0;
public void run() {
System.out.println(count++);
if (count == 10) {
Future<?> future;
while(null==(future = f[0])) Thread.yield();//prevent exceptionally bad thread scheduling
future.cancel(false);
return;
//cancel self
}
}
}, 1, 1, TimeUnit.SECONDS);
Just saw this now... because I wanted to do the same thing... here is my solution, I suspect this is threadsafe.
First create a container for the Future:
public static class Cancel {
private ScheduledFuture<?> future;
public synchronized void setFuture(ScheduledFuture<?> future) {
this.future = future;
}
public synchronized void stop() {
LOG.debug("cancelling {}", future);
future.cancel(false);
}
}
And then the future code:
final Cancel controller = new Cancel();
synchronized (controller) {
ScheduledFuture<?> future = scheduler.scheduleWithFixedDelay(() -> {
if (<CONTINUE RUNNING CONDITION) {
} else {
// STOP SCHEDULABLE FUTURE
controller.stop();
}
}, startTime, timeBetweenVisbilityChecks);
controller.setFuture(future);
}
}
So notice how the stop will not be callable until the future has been created and the future has been set on the controller.
Bear in mind that the Runnable is the anomymous inner class and this will get run in a different thread altogether.