Этот вопрос можно поставить и по-другому: основной поток завершается последним?
теоретический анализ
Когда вы запускаете приложение Java, система создает процесс, выделяет различные ресурсы, а затем процесс запускает основной поток.
Как правило, мы обращаемся к главному потоку в качестве основного потока, потому что другие потоки обычно начинаются в основном потоке.
Но на самом деле на уровне процесса main — это обычный поток, просто некоторые другие потоки запускаются им.
Мы можем догадаться, что: при нормальных обстоятельствах основные потоки запускают другой поток, каждый из них выполняет, не будет влиять друг на друга.
Основание для предположения: поскольку операционная система выделяет ресурсы процессу, даже если основной поток завершается, процесс все еще существует. Ресурсы все еще существуют. С точки зрения процесса все потоки должны быть равными, и нет отношения родитель-ребенок.
Проверка практики
Мы моделируем пример пула потоков, запускаем пул потоков из основного потока и позволяем основному потоку генерировать исключение для завершения при возникновении исключения, чтобы увидеть, продолжает ли работать пул потоков.
Здесь в Интернете ведутся споры о том, что метод печати не может определить, завершен ли основной поток, поэтому в нашем примере используется аварийное завершение и используется инструмент jconsole для проверки.
public class ThreadPoolException {
ExecutorService threadPool = Executors.newFixedThreadPool(5);
public static void main(String[] args) {
ThreadPoolException t = new ThreadPoolException();
t.futureGet();
}
void futureGet() {
for (int i = 0; i < 5; i++) {
Future future = threadPool.submit(() -> {
System.out.println("current thread name" + Thread.currentThread().getName());
Object object = null;
System.out.print("result## " + object.toString());
});
try {
future.get();
} catch (Exception e) {
System.out.println(Thread.currentThread().getName() + "异常");
// 让主线程多等一段时间,便于观察.
try {
Thread.sleep(10000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
//主线程终止
throw new RuntimeException(Thread.currentThread().getName() + "异常");
}
}
}
}
Мы можем наблюдать в jconsole в:
Сначала появляется основной поток, а затем исчезает, а потоки в пуле потоков все еще находятся в состоянии ожидания. Такой же вывод можно сделать и при запуске кода непосредственно в идее.
Суммировать
- JVM завершит работу после того, как будут выполнены все потоки, не являющиеся демонами (пользовательские потоки);
- Основной поток — это пользовательский поток;
- Выполняются только основной поток и один пользовательский поток, и он не может решить, выйдет ли JVM, то есть основной поток не обязательно является последним потоком для выхода.
Если вы хотите выйти после основного потока, все остальные потоки также завершатся.Тогда вы можете установить другие потоки в демон, то есть setDaemon (TRUE). Для пулов потоков вы можете вручную выполнять некоторую обработку при выходе из основного потока, например, Завершение работы и другие методы.