gpa
gpa

Reputation: 2451

Executor shutdownNow with blocked tasks?

I am using Executors for thread pool, and submitting tasks. Can executorService.shutdownNow will shutdown all the tasks even though some of them may be blocked on I/O calls to database or Socket?

Upvotes: 2

Views: 1897

Answers (4)

Chomeh
Chomeh

Reputation: 1066

When its not possible to handle interrupts (java.io), non-standard shutdown logic is required.

My solution to encapsulating this problem combines the examples 'TrackingExecutorService' and 'SocketUsingTask' from 'Java Concurrency In Practice'.

  • Define a 'Shutdownable' interface
  • Extend ThreadPoolExecutor to track running submitted tasks that implement the 'Shutdownable' interface
  • override ThreadPoolExecutor's shutdownNow to invoke non-standard shutdown logic via the 'Shutdownable' interface


    public interface Shutdownable {
        public void shutdown();
    }

    public class ShutdowningExecutor extends ThreadPoolExecutor{
        private final Set runningShutdownables 
            = Collections.synchronizedSet(new HashSet());

        @Override
        protected RunnableFuture newTaskFor(final Callable callable){
            if (callable instanceof Shutdownable) {
            runningShutdownables.add((Shutdownable) callable);          
            return super.newTaskFor(new Callable(){
                    @Override
                    public T call() throws Exception {
                T t = callable.call();
                runningShutdownables.remove((Shutdownable) callable);
                        return t;
                    }
                 });
            } else
                return super.newTaskFor(callable);
        }

        public void shutdownAll() {
            for(Shutdownable shutdownable : runningShutdownables) {
                shutdownable.shutdown();
            }
        }

        @Override
        public List shutdownNow(){
            shutdownAll();
            return super.shutdownNow();
        }
    }

    public abstract class ShutdownableViaCloseable implements Shutdownable{
        private Closeable closeable;

        protected synchronized void setCloseable(Closeable c) { closeable = c; }

        public synchronized void shutdown() {
           try {
               if (closeable != null)
             closeable.close();
           } catch (IOException ignored) { }
       }
    }

    public class MySocketTask extends ShutdownableViaCloseable implements Callable {
        public MySocketTask(Socket s) {
            setCloseable(s);
            //constructor stuff
        } 

        public Void call() {
            try (Socket socket = this.socket) {
                while(!socket.isClosed) {
                    //do stuff
                }
            }
        }
    }

Upvotes: 1

Tom
Tom

Reputation: 1803

It depends on whether your tasks are well written!

The documentation says: "The shutdown() method will allow previously submitted tasks to execute before terminating, while the shutdownNow() method prevents waiting tasks from starting and attempts to stop currently executing tasks."

However, Java doesn't kill threads "out of thin air". It tries to interrupt them. A good task will throw an InterruptException of some sort when shtudownNow tries to interrupt them, and end gracefully. You mention socket communication- most decent clients' blocking methods will throw an interrupted exception if they are interrupted.

An example of a bad task might be (rather obviously) to run a thread with while(true) { readChunk(); if(endOfChunks) { break;} }. This offers no graceful interrupt check! It's the old rule not to use while loops to wait, but to wait() using syncronized on a 'blocker' object that can be interrupted.

Upvotes: 4

skirsch
skirsch

Reputation: 1747

Simply put: you cannot rely on that. The ExecutorService simply interrupts the running tasks; it is up to the implementation of the tasks if they really cancel their endeavor. Some I/O can (and will) be interrupted, especially the java.nio stuff, but the java.io is most likely not interrupted. See What does java.lang.Thread.interrupt() do? for a bit more explanation.

Upvotes: 0

AllTooSir
AllTooSir

Reputation: 49412

No, there is no guarantee. If you see the API doc for ExecutorService#shutdownNow. It says,

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks.

If you want to block until all tasks have completed execution after a shutdown request,use ExecutorService#awaitTermination.

Upvotes: 1

Related Questions