How to shutdown CompletionService after completing currently executed tasks - java

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();

Related

How to delay a scheduled task with Spring?

I'd like to create a method that delays the execution on method invocation by 60s.
Problem: if the method is called within that 60s, I want it to be delayed again by 60s from last point of invocation. If then not called within 60s, the execution may continue.
I started as follows, but of course this is only a one-time delay:
public void sendDelayed(String info) {
//TODO create a task is delayed by +60s for each method invocation
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.schedule(Classname::someTask, 60, TimeUnit.SECONDS);
}
How could I further delay the execution on each invocation?
executorService.schedule returns a ScheduledFuture which provides a cancel method to cancel its execution. cancel takes a single boolean parameter mayInterruptIfRunning which, when set to false, will only cancel the execution if the task has not started yet. See also the docs.
Using this you could do something like this:
private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> future;
public void sendDelayed(String info) {
// When there is a task that has not been started yet, stop it:
if (future != null) {
boolean cancelled = future.cancel(false);
if (cancelled) {
logger.debug("Task has been cancelled before execution");
} else {
logger.debug("Task is already running or has been completed");
}
}
// Old task has been cancelled or already started - schedule a new task
future = executorService.schedule(Classname::someTask, 60, TimeUnit.SECONDS);
}
You may have to take care of avoiding race conditions regarding concurrent access to the future field though.

ExecutorService: get a list of submitted tasks and cancel all tasks without shutting down the executor

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.

ScheduledExecutorService and ThreadPoolTaskExecutor that interrupts tasks after a timeout

I Used ExecutorService that interrupts tasks after a timeout.I use a ScheduledExecutorService for this. First I submitted the thread and it once to begin immediately and retain the future that is created. After that i use ScheduledExecutorService as a new task that would cancel the retained future after some period of time.
//Start Spring executor to submit tasks
ThreadPoolTaskExecutor taskExecutor = (ThreadPoolTaskExecutor) ApplicationContextProvider.getApplicationContext().getBean("taskExecutor");
CompletionService completionService = new ExecutorCompletionService(taskExecutor);
//End Spring executor to submit tasks
// Start ScheduledExecutorService to submit returned future object to timeout
ScheduledExecutorService executor = Executors.newScheduledThreadPool(Integer.parseInt(config.getProperty("DBPOLLER_COREPOOLSIZE")));
final Future<String> future = completionService.submit(batchJob); // Submit actual task and get future
// submit future
executor.schedule(new Runnable() {
public void run() {
future.cancel(true);
}
}, dbPollerTimeOut, TimeUnit.MINUTES);
int count = taskExecutor.getActiveCount();
if (count == 0) {
taskExecutor.shutdown();
executor.shutdown();
finalExitStatus = 0;
break;
}
I have implemented the solution which is in below url:
ExecutorService that interrupts tasks after a timeout, it was working fine, until timeout, but once timeout happens, it cancels all theenter code here tasks i ThreadPool which is not acceptable. I need to cancel only tasks that are long running and reach timeout.
Any idea how to achieve this?
It is not clear what your CompletionService is, and you are submitting your batchJob on it, so it is hard to tell exact root cause of your problem. But ideal scenario of submitting few tasks and cancelling them after some time, is to use ScheduledExecutorService for both purposes.
So, can try submitting the batchJobon instance of ScheduledExecutorService i.e. executor.
final Future<String> future = executor.submit(batchJob); // Submit actual task and get future
EDIT UPDATE: Important change you SHOULD do in your code
I see that you are never stopping your ScheduledExecutorService which is wrong because resources it occupies will never be released until you stop it. So, your updated code should be as below:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(Integer.parseInt(config.getProperty("DBPOLLER_COREPOOLSIZE")));
final Future<String> future = executor.submit(batchJob); // Submit actual task and get future
executor.schedule(new Runnable() {
public void run() {
future.cancel(true);
executor.shutdownNow();
}
}, dbPollerTimeOut, TimeUnit.MINUTES);

executor cancel pending task - help needed

Basically, I need a machinery to have the following:
Fixed-sized thread pool to run tasks
Queue of pending tasks (requested, but not yet running)
Cancelling task in pending queue (task is identified by id)
Cancelling ongoing task
Given task id, query whether task is Pending or Running
Could anyone suggest best way of achieving this, especially items 3-5. I would really appreciate some code example.
Thanks.
Everything but task states and cancelling is standard for thread pools. Cancellations and status state could be done the following way:
enum TaskState {PENDING, RUNNING};
abstract class MyCallable<V> implements Callable<V>{
protected volatile TaskState state = PENDING;
// to make sure state is always set before running the task
protected abstract V doCall();
final V call(){
state = RUNNING;
return doCall();
}
public TaskState getState() { return state; }
}
...
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<V> future = executor.submit(new MyCallable<V>() {
public V doCall() throws Exception {
//... some work ...
if(Thread.interrupted()){
removeFromMap();
return null;
}
}
});
...
future.cancel(true);
To make task cancellable one needs to check Thread.interrupted() state during it's execution or some other logical boolean flag. After getting a future for the submitted task, future.cancel(true) should be called to cancel the task by interrupting it.
Everything you need is in the tags. If you use a fixed thread pool ExecutorService, you can limit the number of threads that can execute simultaneously.
If more threads are submitted than can be handled, they are held in a queue.
Calling the submit() method of an ExecutorService will give you a Future object which will let you know whether the task is pending or it has been cancelled, etc
I do have a series of tutorials on ExecutorService: http://codelatte.wordpress.com/2013/11/09/a-simple-newfixedthreadpool-example/
How to use Future object: http://codelatte.wordpress.com/2013/11/08/a-simple-cachedthreadpool-example/

Waiting in main Thread till a canceled Executor Task is finished

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();

Categories