javaserviceexecutorcompletiontake

Java thread hangs after CompletionService.take()


I've got simple test code:

public static void main(String[] args) {
    CompletionService<Integer> cs = new ExecutorCompletionService<>(Executors.newCachedThreadPool());
    cs.submit(new Callable<Integer>() {
        public Integer call(){
            try{
                Thread.sleep(3000); // Just sleep and print
                System.out.println("Sleeping thread: " + Thread.currentThread().getId());
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            return 10;
        }
    });
    try{
        Future<Integer> fi = cs.take();
        System.out.println(fi.get());
    }catch(Exception e){
        e.printStackTrace();
    }
}

I run it, sleep 3 seconds, and prints

Sleeping thread: 14
10

But then it hangs there, the program doesn't end.

What's happening, how to make it finish?


Solution

  • As mentioned in the comments by tgdavies, your program will exit after +/- 60 seconds, because that is the default timeout for a thread without tasks in an ExecutorService created by Executors.newCachedThreadPool().

    If you don't want to wait for 60 seconds, you should shutdown the executor service after you're done submitting tasks.

    For example:

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        try {
            CompletionService<Integer> cs = new ExecutorCompletionService<>(executorService);
            cs.submit(new Callable<Integer>() {
                public Integer call() {
                    try {
                        Thread.sleep(3000); // Just sleep and print
                        System.out.println("Sleeping thread: " + Thread.currentThread().getId());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return 10;
                }
            });
            try {
                Future<Integer> fi = cs.take();
                System.out.println(fi.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        } finally {
            executorService.shutdown();
        }
    }
    

    Alternatively, configure the executor service to create daemon threads using a custom ThreadFactory. Only do this if it is not a problem that an executor service that is doing actual work gets "killed" when there are no more normal (non-daemon) threads.