i have a ScheduledExecutorService (with newScheduledThreadPool( 1)) where i add tasks like this:
myTask = scheduler.scheduleAtFixedRate(new Runnable() {
#Override public void run() {
// do work
}
},
delay,
interval,
TimeUnit.MILLISECONDS );
I have a list of all my tasks. If i for example want to remove a task i can do this (e.g. the first task)
myTaskList.get(0).getTask().cancel(true);
My problem now is that if the task i want to cancel is currently running in the scheduler thread i have to wait in the main-thread till the task is canceled. I thought i could do this with get() like this:
myTaskList.get(0).getTask().cancel(true);
myTaskList.get(0).getTask().get();
but my main-thread goes on without waiting for the task code to finish.
For clarity, what i want is basically this:
User wants to cancel task
If to be canceled Task is the one currently running in the scheduler thread the main-thread have to wait till the task is no longer the one executing in the scheduler thread
If I truly understood your mean, you want main method waits for child thread to finish/stop. Is it true? If so, You can use method join() in the main method. This method forces main method to wait for child thread to stop/finish. This method is in class java.lang.Thread.
I don't think this would work in practice. When you attempt a get() on a canceled Future it will throw a CancellationException as per API
#throws CancellationException - if the computation was cancelled
What you could try is to map the Future with a CountdownLatch maybe something like this
class LatchedFuture{
volatile Future future;
final CountdownLatch latch = new CountdownLatch(1);
}
final LatchedFuture latchedFuture = new LatchedFuture();
latchedFuture.future = scheduler.scheduleAtFixedRate(new Runnable() {
#Override public void run() {
// do work
latchedFuture.latch.countDown();
}
},
delay,
interval,
TimeUnit.MILLISECONDS );
Then when you want it to finish.
myTaskList.get(0).getTask().future.cancel(true);
myTaskList.get(0).getTask().latch.await();
Related
I have an ExecutorService that I submit tasks to:
private final ExecutorService CUSTOM_POOL = Executors
.newCachedThreadPool();
private Queue<Future<?>> customTasksHandles;
private boolean started;
private Runnable task = new Runnable() {
#Override
public void run() {
if (!started) {return;}
...
customTasksHandles.add(CUSTOM_POOL.submit(new CustomTask(customData)));
...
}
}
I need to create public void stop() and public void start() functions. The stop() function would future.cancel() for every task that has been submitted to the executor, while the start() would start running the task Runnable again.
public void stop() {
...
Future customTasksHandle= customTasksHandles.poll();
while (customTasksHandle!=null) {
customTasksHandle.cancel(true);
customTasksHandle=locationTasksHandles.poll();
}
...
started = false;
}
public void start() {started = true;}
I tried to just CUSTOM_POOL.shutdown(), however it seems to make it impossible to submit new tasks later, after the start() is called. It seems that the only way is to loop over all submitted tasks and call .cancel() on each.
However, how do I get all submitted tasks without adding each task to a list/queue when submitting? Is there a better way to do it other than the way above? I was hoping for a List<Future> submittedTasks = CUSTOM_POOL.getAllSubmittedTasks() method of sorts, but there doesn't seem to be one. Interestingly, .shutdown() and invoke() methods do return List<Future>, but have side-effects.
As you can see here you could use the shutdownNow() method to stop and retrieve all the task that where waiting for execution. If what you want is just stop ("pause") the procesing of the task and the continue with it, you migth want to keep track yourself of the status of the taks and when you pause and unapuse the task you can resubmit the task returned by the mehtod shutdownNow() and the one that where executing in the instant of the stop. You should take into account that to stop the threads the pool may call thread interrupt so, if you are executing some sensible work you should take care of it properly. There is no pause and unpause for threads. check this
You can achieve this by using Future, create start method which accepts Runnable and return Future
public Future<?> start(Runnable run) {
return CUSTOM_POOL.submit(run);
}
You can save all these Future in a List or Map so that you can cancel which ever you need by using custom stop method
public void stop(Future<?> future) {
future.cancel(true);
}
Example
public class TestMain {
private final ExecutorService CUSTOM_POOL = Executors
.newCachedThreadPool();
public static void main(String[] args) {
//custom logic
}
public Future<?> start(Runnable run) {
return CUSTOM_POOL.submit(run);
}
public void stop(Future<?> future) {
future.cancel(true);
}
}
Future
Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. 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.
In Android, I'm trying to start a thread that kills itself or is canceled by the executor after some timeout limit for example 20 seconds? So the runnable would only do its work for that many seconds than cancel...
How do I achieve this? I'm currently starting it as the following.
Executors.newSingleThreadScheduledExecutor().schedule(myRunnable, 0, TimeUnit.MILLISECONDS);
My runnable looks like this
static class MyRunnable implements Runnable {
MyRunnable(Helper _helper) {
helper = _helper;
}
public void run() {
}
}
If you want to stop a task that has already been submitted to an ExecutorService then you'll need to deal with Future objects.
Like this answer:
Stop a Runnable submitted to ExecutorService
Basically you will submit a Runnable and get back a Future object that you can use to cancel it.
Specific to your concern: Stop one task in 20 seconds you could use handoff the Future object from the first task to another like so:
ExecutorService executor = Executors.newSingleThreadScheduledExecutor();
// Schedule your audio processing job like normal.
final Future<?> future = executor.submit(new MyAudioProcessingRunnable())
// Schedule the cancelation to happen in 20 seconds.
executor.schedule(new Runnable() {
if (!future.isCancelled() && !future.isDone()) {
// Cancel and interrupt any blocking calls.
future.cancel(true);
}
}, 20, TimeUnit.Seconds);
IMPORTANT - You must have code in your MyAudioProcessingRunnable to support cancelation.
I have something like this:
ExecutorService executor = Executors.newFixedThreadPool(2);
CompletionService<Boolean> completionService = new ExecutorCompletionService<>(executor);
int i = 0;
while (i < 40) {
completionService.submit(getTask());
i++;
}
executor.shutdown();
System.out.println("SHUTDOWN");
After calling shutdown all submitted tasks are executed. If I call shutdownNow, then currently executed threads are throws java.lang.InterruptedException.
Is there are any way to wait currently executed tasks to complete and don't execute other submitted tasks?
shutdown() allows the currently submitted tasks to complete, but rejects new ones:
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
If you want to wait in your main thread for the executor to shut down, you can invoke executor.awaitTermination(long timeout, TimeUnit unit):
Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
If you want to allow the tasks that are currently running to complete, but discard the ones that are already submitted to the queue, you have a few choices:
cancelling the Futures with cancel(false):
Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run.
Returns:
false if the task could not be cancelled, typically because it has already completed normally; true otherwise
wrapping your Runnable/Callable with a custom CancellableRunnable/Callable (depending on what your getTask() returns):
class CancellableRunnable implements Runnable {
private final AtomicBoolean shouldRun;
private final Runnable delegate;
public CancellableRunnable(AtomicBoolean shouldRun, Runnable delegate) {
this.shouldRun = shouldRun;
this.delegate = delegate;
}
#Override
public void run() {
if (shouldRun.get()) {
delegate.run();
}
}
}
and the usage in your example:
AtomicBoolean shouldRun = new AtomicBoolean(true);
while (i < 40) {
completionService.submit(new CancellableRunnable(shouldRun, getTask()));
i++;
}
shouldRun.set(false);
executor.shutdown();
Yes, after you have called shutdown(), the executor will accept no new tasks. Next you call awaitTermination() to await running tasks completing.
If all you want is the first two results and then discard the other tasks, you can wait for the first two tasks to be completed then cancel the others, for example by calling shutdownNow if you don't need the completion service any longer.
Future<Boolean> result1 = copmletionService.take();
Future<Boolean> result2 = copmletionService.take();
completionService.shutdownNow();
I have 2 snippets of codes, one uses ScheduledExecutorService to execute a Thread at a certain time, the other uses Timer to execute a TimerTask at a certain time. The problem is while using ScheduledExecutorService, even though the thread's run() reaches the end, a monitor program indicates that it is still alive (see image bellow). The TimerTask, on the other hand, ends its thread once the execution is completed.
I have changed ScheduledExecutorService's Thread to TimerTask but received the same result. How do I resolve the issue while using ScheduledExecutorService?
Timer:
TimerTask task = new TimerTask()
{
#Override
public void run()
{
System.out.println("doing something");
}
};
Timer t = new Timer();
t.schedule(task, 250);
ScheduledExecutorService:
Thread task = new Thread()
{
#Override
public void run()
{
System.out.println("doing something");
}
};
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.schedule(task, 250, TimeUnit.MILLISECONDS);
In your second snippet, you've created a Thread instance but the ScheduledExecutorService has used the instance as a Runnable, ie. it only cares about its run method. It doesn't actually start the Thread.
ScheduledExecutorService maintains its own Thread(s) for executing tasks. With newSingleThreadScheduledExecutor, this is a single non-daemon Thread. You'll need to shutdown the ScheduledExecutorService for that Thread to complete.
The javadoc of Timer states
After the last live reference to a Timer object goes away and all
outstanding tasks have completed execution, the timer's task execution
thread terminates gracefully (and becomes subject to garbage
collection).
After it has executed your TimerTask, it will complete its internal thread.
I am writing code where I need to make sure that no threads are currently running in a thread pool before I commit results (to avoid losing data I should have put in the commit). For that, I'm using:
while (_executor.getActiveCount() > 0)
{
try
{
Thread.sleep(10); // milliseconds
}
catch (InterruptedException e)
{
// OK do nothing
}
}
But a colleague pointed out in review that the doc for getActiveCount states:
Returns the approximate number of threads that are actively
executing tasks.
So, is there a risk I would get out of the while loop while there are still active threads in the pool? If so, what would be the correct way to wait for all my worker threads to be done?
Edit: To give some more context: this is an online system, where the task that contains the executor service is left running indefinitely. Work comes in via a messaging system, is put on a thread in the executor, which doesn't need any synchronization, and works come out into another queue for the messaging system. I don't want to kill the executor to wait for completion of tasks.
You might want to consider using a CompletionService (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CompletionService.html).
A CompletionService wraps an ExecutorService and returns a Future when tasks are submitted. By maintaining a list of these Futures, you can see if the jobs that you're waiting on have completed. It also has the additional advantage that you can have others use the same ExecutorService since you have some means of accounting,
_executor.awaitTermination(); should do the job. Now, it won't actually wait for the threads to shutdown, but rather it would wait for all available tasks to terminate.
You could also provide keepAliveTime to a thread pool constructor to instantly terminate idle threads:
ExecutorService executor = new ThreadPoolExecutor(0, 10, 0L /* keepAlive */,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
To notify a thread that it should clean up and terminate, use the interrupt method.
t.interrupt();
and it is good to print or have log of your errors from catch block.
When tasks are submitted to the executor, they return Futures, which indicate when they complete. That is the preferred mechanism to use.
You can use JDK ExecutorService shutdown/awaitTermination.
Use case: need to cleanup thread-locals in pool threads upon their completion and this cleanup can take long (e.g. connection close). Only after that the main thread can continue.
A worker thread can register itself in some collection. For that override start() and run() and pass a custom thread factory to ThreadPoolExecutor:
class MyThreadFactory implements ThreadFactory {
#Override
public Thread newThread(final Runnable r) {
return new MyThread(r);
}
...
class Some {
void waitAllThreads() {
Thread worker;
while ((worker = workerThreads.poll()) != null) {
worker.join();
}
}
...
class MyThread extends Thread {
#Override
public synchronized void start() {
if (getState() == State.NEW) {
some.workerThreads.offer(this);
}
super.start();
}
#Override
public void run() {
try {
super.run();
} finally {
some.workerThreads.remove(this);
}
}
...