Xavi López
Xavi López

Reputation: 27880

Shutting down an ExecutorService from running task

I'm using a single threaded ScheduledExecutorService in order to process some Runnable tasks. When my Runnable has finished its work, it reschedules itself in the ScheduledExecutorService with a variable delay. This happens indefinitely until the Runnable catches an Exception.

public class Runner { 

    ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

    public void startWorking() { 
        // Single-shot start
        service.submit(new Task(service));
    }

    public void stopWorking() { 
        service.shutDown();
        // Do some other stuff
    }

    private static final class Task implements Runnable { 
        ScheduledExecutorService service;
        private Task(ScheduledExecutorService service) {
            this.service = service;
        }
        @Override 
        public void run() { 
            try { 
                // Do some work...
                service.schedule(this, variableDelay, TimeUnit.SECONDS);
            }
            catch(SomethingHappenedException e){ 
                // Shutdown service
            }
        }
    }   
}

Can I shutdown() or shutdownNow() the ExecutorService safely from Task.run()? Something doesn't look right if the thread will be provoking an interrupt to itself.

When an exception is caught while executing Task, I'd like to shutdown the service, ideally calling Runner.stopWorking().

I know I could use a Callable instead and let Runner manage reschedulings, but I'd like to keep this structure (Runner will have more analogous services, so an infinite loop just doesn't look right there).

I guess I could subclass ScheduledThreadPoolExecutor to override afterExecute and handle shutdown there, using a reference to Runner.

public class Runner { 
    ScheduledExecutorService service = new ScheduledThreadPoolExecutor(1){
      protected void afterExecute(Runnable r, Throwable t) { 
        if (t != null) { 
            Runner.this.stopWorking();
        }
    };
    // ...
}

My concern with this approach is, if afterExecute will be invoked by the thread that ran the Task, this would have the same effects as calling shutDown() from Task.run() itself.

Is there any other alternative approach to this?

Upvotes: 1

Views: 2186

Answers (1)

Antoniossss
Antoniossss

Reputation: 32535

Can I shutdown() or shutdownNow() the ExecutorService safely from Task.run()? Something doesn't look right if the thread will be provoking an interrupt to itself.

shutdown() will not interrupt already running tasks but will prevent new task from beeing submited. shutdownNow() doesn't interrupt running tasks either, but "signals" all workers that they should be terminated. It is up to Thread implementation (or rather Runnable itself) will it honor such signal (Thread.isTerminated() as I remember) or not.

And yes, it is perfectly fine for thread to signal itself to be terminated. So it is safe to shutdown() executor from running task.

Upvotes: 5

Related Questions