Home > OS >  When using a thread pool, call Future#get and the program hangs
When using a thread pool, call Future#get and the program hangs

Time:11-21

I created a thread pool, and submitted two tasks. Why does my application hang without any exceptions after print task one ,result: null???

   private final static ThreadPoolExecutor executorService = new
        ThreadPoolExecutor(1, 1, 1L, TimeUnit.MINUTES,
        new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.DiscardPolicy());

    public static void main(String[] args) throws Exception {
        Future taskOne = executorService.submit(() -> {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Future taskTwo = executorService.submit(() -> System.out.println("task two is working"));;
        System.out.println("task one ,result: "   taskOne.get());
        System.out.println("task two, result: "   taskTwo.get());
        executorService.shutdown();
    }

CodePudding user response:

When you submit the second task, the rejection policy is triggered because the thread pool uses SynchronousQueue and maximumPoolSize is 1, while the first task has not completed. You are using DiscardPolicy, which means that the thread pool does nothing and returns you a FutureTask whose state is always NEW.

    public static class DiscardPolicy implements RejectedExecutionHandler {
        public DiscardPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

So when you call taskTwo#get(), you will always be blocked. (FutureTask will always be blocked when it is in a state smaller than COMPLETING, see FutureTask#get).

You can use AbortPolicy (the default policy), so that when you execute executorService.submit(() - > submit; System.out.println("task two is working")), you immediately get a RejectedExecutionException.

Or use Future#get(timeout), in which case you get a TimeoutException if you do not get a result for a specified time.

CodePudding user response:

new ThreadPoolExecutor.DiscardPolicy() silently discards the new task when it fails to submit it. here taskTwo wants to get executed, it never gets a chance to execute.

DiscardPolicy() method internally call void rejectedExecution(Runnable r, ThreadPoolExecutor executor) from RejectedExecutionHandler interface.

I have shown CustomRejectedExecutionHandler for better understanding the taskTwo thread condition. As taskTwo is silently discarded so that taskTwo.get() method will never be able to return data.

That's why timeout is required to be set as 1 second (taskTwo.get(1000, TimeUnit.MILLISECONDS)).

package example;

import java.util.concurrent.*;

public class ThreadPoolEx {

    public static void main(String[] args) {
        CustomRejectedExecutionHandler rejectionHandler = new CustomRejectedExecutionHandler();
        ThreadPoolExecutor executorService =
                new ThreadPoolExecutor(1, 1, 1L,
                        TimeUnit.MINUTES,
                        new SynchronousQueue<Runnable>(),
                        rejectionHandler
                );


        Future taskOne = executorService.submit(() -> {
            try {
                System.out.println("taskOne is going to sleep");
                Thread.sleep(2000);
                System.out.println("taskOne is wake up");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Future taskTwo = executorService.submit(() -> System.out.println("task two is working"));
        try {
            System.out.println("task one ,result: "   taskOne.get());
            System.out.println("isTerminating "  executorService.isTerminating());
            System.out.println("getActiveCount "  executorService.getActiveCount());
            System.out.println("is cancelled "   taskTwo.isCancelled());
            System.out.println("is isDone "   taskTwo.isDone());
            System.out.println("task two, result: "   taskTwo.get(1000, TimeUnit.MILLISECONDS));
        } catch (Exception e) {
        }
        executorService.shutdown();
    }
}

class CustomRejectedExecutionHandler implements RejectedExecutionHandler {

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println(r.toString()   " is rejected");
    }
}
  • Related