1

As we know, the java.util.concurrent.Executors contains many methods such as

  • newCachedThreadPool

  • newFixedThreadPool

  • newScheduledThreadPool

  • newSingleThreadExecutor

  • newSingleThreadScheduledExecutor

    They return ExecutorService, which contains the execute(Runnable task) method. However, when calling the execute(Runnable task) of ExecutorService returned from the aforementioned factory methods, it could only terminate by calling shutdown() or shutdownNow()

For instance, if we add the following code to the main method,

ExecutorService e = Executors.newSingleThreadExecutor();
e.execute(() -> system.out.println("test")); 

the calling the the main program will never terminate as the shutdown() or shutdownNow() is not called. So a program containing the following snippet in main will terminate

ExecutorService e = Executors.newSingleThreadExecutor();
e.execute(() -> system.out.println("test"));
e.shutdown();

However, some subclasses of ExecutorService such as the one returned by calling Executors.newWorkStealingPool or the ForkJoinPool can terminate without calling shutdown() or shutdownNow()

So my QUESTION is: why does the execute() of the ExecutorService returned from the aforementioned factory methods starting with "new" not terminate without calling shutdown() or shutdownNow() from the design point of view?

Community
  • 1
  • 1
Rui
  • 3,454
  • 6
  • 37
  • 70
  • Can not understand what you are asking – Scary Wombat Jun 08 '18 at 06:40
  • Those factory methods return ExecutorService objects, whi are not the same thing as the execution submitted to them using `.execute`. Why do you need to compare those two? – ernest_k Jun 08 '18 at 06:44
  • Can you add the code of the `Runnable` you are using ? – soufrk Jun 08 '18 at 07:06
  • @ErnestKiwele I would like to know why the returned `ExecutorService`, mostly is the `ThreadPoolExecutor`, was designed in such way – Rui Jun 08 '18 at 07:08

2 Answers2

0

Rui, the answer for why your example hangs is simple. By default, the threads in the ExecutorService are non-daemon threads and a Java program won't exit as long as there are non-daemon threads running. If you don't want this behavior all you need to do is define a ThreadFactory that creates daemon threads, like this:

public class Test {
    static ThreadFactory mThreadFactory = new ThreadFactory() {
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setDaemon(true);
            return t;
        }
    };

    public static void main(String[] args) {
        ExecutorService e = Executors.newSingleThreadExecutor(mThreadFactory);
        e.execute(new Runnable() { public void run() { System.out.println("test"); } });
    }
}
  • Thanks a lot for your reply. Good for me to review the daemon threads. However, if we do so, I am afraid that even the program running the `ExecutorService` terminated, the generated daemon threads are still running in the background, isn't it? – Rui Jun 10 '18 at 08:52
0

Briefly about java threads: there are two types of threads - daemon and non-daemon. The program terminates when all of its non-daemon threads have finished execution. Daemon threads can only run as long the program is running and do not block termination, e.g. garbage collector. When a java program starts all of its threads except the main thread are daemon.

newSingleThreadExecutor() and its defaultThreadFactory() create non-daemon threads. Which kinda makes sense - you're creating a pool of threads that wait for work, it should be your explicit intention to shut it down.

ForkJoinPool, on the other hand, abstracts you from the underlying thread pool. So it can use daemon threads, as it is generally your intention to wait for task execution anyways.

Denis Tulskiy
  • 19,012
  • 6
  • 50
  • 68
  • It would be nice to show an example using CompleteableFuture: CompletableFuture.runAsync(() -> System.out.println("test")); – kensei62 Jul 14 '20 at 17:28