Необходимо ли завершать работу исполнителя, возвращаемого Executors.newVirtualThreadPerTaskExecutor()?

Project loom представил службу исполнителя виртуальных потоков Executors.newVirtualThreadPerTaskExecutor(), которая создает новый виртуальный поток (VT) каждый раз, когда мы отправляем задачу.

У меня есть пара вопросов по этому поводу:

  1. Java ничего не объединяет и создает новый VT для каждой задачи. необходимо ли выключать пул виртуальных потоков? Если да, то что он делает внутри?
  2. если требуется отключение, то как очистить ВТ, созданные с помощью Thread Factory threadFactory.newThread()

Я просмотрел Virtual Thread JEP, и, кажется, там ничего не упоминается по этой теме.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
0
309
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вам необходимо завершить работу, если вы хотите быть уверены, что служба-исполнитель не принимает новые задачи, и если вы хотите иметь возможность дождаться завершения всех ранее отправленных задач.

А поскольку виртуальные потоки всегда являются потоками демона, ожидание завершения требуется, если вы хотите быть уверены, что все ваши задачи завершены, прежде чем вы выйдете из приложения.

Таким образом, если вас не волнует, были ли задачи, отправленные в службу исполнителя виртуальных потоков, завершены до выхода JVM, вам не нужно ее выключать, но в противном случае вам действительно нужно выключиться и дождаться завершения.

Для очистки виртуальных потоков не требуется ничего особенного. Как только они закончатся, они исчезнут.

Как очистить потоки, если я использую ThreadFactory? По какой-то причине я создаю VT с помощью фабрики и украшаю ее перед вызовом потока.

Govinda Sakhare 12.04.2024 15:54

@GovindaSakhare Если вы не делаете что-то странное в своей фабрике потоков, вам не нужно ничего делать для очистки потока. В противном случае вам действительно следует задать отдельный вопрос об этом и предоставить минимально воспроизводимый пример, который показывает вашу фабрику нитей и четко объясняет вашу обеспокоенность.

Mark Rotteveel 12.04.2024 15:56

Но это может и не потребоваться, если реализация использует try-with-resources или любой другой способ гарантировать закрытие ресурса. Разве не в этом цель расширения AutoCloseable для самой ExecutorService?

Naman 12.04.2024 19:11

@Naman Хотя это правда, по моему опыту, многие варианты использования службы-исполнителя не позволяют использовать попытку с ресурсами и, как правило, отключаются при каком-то окончательном действии очистки (например, как часть завершения работы приложения). Тем не менее, я не так много работал с функциями Java 21 и совершенно упустил из виду, что теперь в ней есть метод close() (начиная с Java 19), который выполняет завершение работы и ожидание.

Mark Rotteveel 12.04.2024 19:17

К вашему сведению, реализация close в OpenJDK аналогична шаблонному коду, приведенному в Javadoc ExecutorService, но с тайм-аутом 1 день.

Basil Bourque 13.04.2024 16:05

Добавляя к другому ответу , если вы ссылаетесь на пример, приведенный в самом JEP, идеальным способом реализации использования такого ExecutorService было бы заключить его в оператор try with resources, и в этом случае выключение и ожидание неявно заботятся о:

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        });
    });
}  // executor.close() is called implicitly, and waits

Это справедливо также из-за изменения в рамках Второго предварительного просмотра JEP , чтобы ExecutorService расширял AutoCloseable , раскрывая единственный абстрактный метод close, для которого

Реализация по умолчанию вызывает shutdown() и ожидает выполнения задач. полное исполнение с awaitTermination.

Кроме того, разработчики не должны объединять виртуальные потоки в пул, поэтому вам не нужно беспокоиться об их очистке. ИМХО, большая часть этого была бы реализована, учитывая, что они сокращают усилия по внедрению и обслуживанию приложений, использующих эту функцию.

Обратите внимание, что этот подход блокирует основной поток до тех пор, пока виртуальный поток не завершится.

Toofy 04.07.2024 10:22

Другие вопросы по теме