У меня была короткая java-программа, которая создавала однопоточный запланированный исполнитель, и я планировал задачу.
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.schedule(cloudWatchReporter, accumulateForMillis, TimeUnit.MILLISECONDS);
До наступления запланированного времени мой основной поток завершился, и JVM закрылась. Я ожидал, что перед завершением работы он дождется завершения таймера и выполнения запланированной задачи. Это не то, что случилось. Если бы я добавил достаточно сна непосредственно перед тем, как мой основной поток завершился, моя задача затем была бы выполнена до завершения работы JVM.
Есть ли у исполнителей главный поток, который управляет таймером? Или эффект таймера достигается каким-то другим способом? Если под управлением какого-либо главного потока, это поток демона или поток, не являющийся демоном?
@SotiriosDelimanolis Я не спрашивал, являются ли потоки в пуле демонами или недемонами. Я спросил, существует ли поток, который создает потоки для пула, и является ли этот поток демоном или не-демоном.
Все потоки в реализации ScheduledExecutorService
JDK извлекают задачи из главной «очереди». Нет никакого «управляющего» потока. Потоки создаются и запускаются по мере необходимости (и максимум до 1 в вашем случае) из потока, вызывающего любой из методов schedule
.
Как работает таймер?
Каждый поток зацикливается, пытаясь получить данные из очереди с общим приоритетом, в течение более или менее продолжительного периода ожидания самого верхнего элемента (если он присутствует).
Этот простой полный пример противоречит тому, что вы утверждаете в своем вопросе:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
class Test {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.schedule(() -> System.out.println("hello"), 10, TimeUnit.SECONDS);
}
}
Запустите его, и вы увидите, что не только сообщение печатается через 10 секунд, но и программа не выходит. Итак, ваш основной поток не просто закончился. Вы, наверное, звоните System.exit()
.
Я запустил предоставленный вами код. Это работает, как вы сказали. Но я не могу заставить эти две строки в основном методе работать одинаково при выполнении в рамках теста JUnit. Тест просто завершается до того, как будет напечатан текст «привет». Выполняется ли тестовый код JUnit иначе, чем из основного метода? Я не упоминал об этом раньше, но мой первоначальный вызов метода расписания происходит из теста JUnit.
Скорее всего, исполнитель JUnit вызывает System.exit () сразу после выполнения всех тестов. Если вы хотите, чтобы запланированное задание выполнялось, вам необходимо заблокировать тест на достаточно длительный период.
См. Javadoc
defaultThreadFactory()
: Возвращает фабрику потоков по умолчанию, используемую для создания новых потоков. Эта фабрика создает все новые потоки, используемые Executor в той же ThreadGroup. [...] Каждый новый поток создается как поток, не являющийся демоном. с приоритетом, меньшим из Thread.NORM_PRIORITY, и максимальным приоритетом, разрешенным в группе потоков. [...]