2

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.

parsecer
  • 4,758
  • 13
  • 71
  • 140
  • For clarification, are you looking to _suspend_ the execution of your tasks and then, when desired, _resume_ execution from that point or are you looking to _cancel_ each task and then, when desired, _resubmit_ the tasks in order to restart them? – Slaw Oct 04 '19 at 18:05
  • @Slaw the later – parsecer Oct 04 '19 at 18:09

2 Answers2

1

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

Javier Toja
  • 1,630
  • 1
  • 14
  • 31
1

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.

Ryuzaki L
  • 37,302
  • 12
  • 68
  • 98
  • Careful. If the OP wants the underlying task execution to actually stop this won't work—cancelling a `CompletableFuture` doesn't interrupt the executing thread. – Slaw Oct 04 '19 at 17:28
  • but from doc it said it will cancel if not completed @Slaw – Ryuzaki L Oct 04 '19 at 17:32
  • 1
    It exceptionally completes the `CompletableFuture` with a `CancellationException` but doesn't affect the actual background task. From [`CompletableFuture#cancel`](https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/concurrent/CompletableFuture.html#cancel(boolean)): "_mayInterruptIfRunning - this value has no effect in this implementation because interrupts are not used to control processing_". – Slaw Oct 04 '19 at 17:35
  • And in the class docs (emphasis mine): "_Since (unlike FutureTask) this class has **no direct control over the computation that causes it to be completed**, cancellation is treated as just another form of exceptional completion. Method cancel has the same effect as completeExceptionally(new CancellationException())_". – Slaw Oct 04 '19 at 17:36
  • Thanks for enlightening me this @Slaw i updated my answer with `Future` object – Ryuzaki L Oct 04 '19 at 17:51
  • The `start()` and `stop()` are supposed not to take *any* arguments. The methods are supposed to start or stop all tasks in executor, not a single task. I've made an edit to show what I currently have - basically saving tasks handles in a queue. I was wondering if there's a better method. Your approach seems to also imply the saving of the task handles elsewhere and then later calling `.start` or `.stop` on each handle. – parsecer Oct 04 '19 at 19:43