Is it possible to return from a java method that started threads before all the threads are done?
Here's my code:
import java.util.concurrent.*;
public class ExecutorSample {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
service.execute(() -> {
while (true) {
}
});
}
return;
}
}
This doesn't return for some reason that I don't understand. Why is the main thread's return affected by the worker threads being stuck?
Your main
method is returning, but the problem is that your JVM isn't exiting. You can test this by renaming your main
method to something else, like doMain()
, and then writing main
as:
public static void main(String[] args) {
doMain();
System.out.printf("here");
}
You'll see that you do get the output, but the program doesn't end.
What's happening is that Executors.newCachedThreadPool
uses the default thread factory, which creates non-daemon threads. When your main
method returns, the JVM will wait for all non-daemon threads to finish (that's what differentiates them from daemon threads -- the JVM doesn't wait for those). Since all of your Runnables run forever, the non-daemon threads will never finish, and the JVM will never exit.
What can you do? Some options:
- Use the overload
newCachedThreadPool(ThreadFactory)
, supplying a ThreadFactory that creates daemon threads - Use
shutdownNow()
on your ExecutorService. That will send an interrupt on each of the running threads. You'll still have to check for that on each thread, either by calling a method that throwsInterruptedException
or by explicitly callingThread.currentThread().isInterrupted()
.
For the shutdownNow
approach, note that interrupting a thread by itself is not enough to stop it -- the code running on that thread has to cooperate by checking for its interrupted state (using one of those two approaches) and appropriately exiting. For instance, you could replace while(true)
with while (!Thread.currentThread().isInterrupted())
.