Java newSingleThreadExecutor сборка мусора

#java #multithreading #executor

#java #многопоточность #исполнитель

Вопрос:

Рассмотрим следующий код Java

 void doSomething(Runnable r1, Runnable r2){
  Executor executor = Executors.newSingleThreadExecutor();
  executor.execute(r1);
  executor.execute(r2);
}
  

когда я вызываю метод doSomething, создается исполнитель, который последовательно выполняет задачи r1 и r2 одну за другой.

Мой вопрос: что произойдет, когда две задачи r1 и r2 завершатся?

Я полагаю, что объект-исполнитель будет собирать мусор, но я не знаю, будет ли он также отключен. Если исполнитель создает новый поток для своего выполнения, приведет ли этот поток к утечке ресурсов?

Комментарии:

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

2. Вы также можете использовать a ThreadPoolExecutor с нулевыми потоками ядра, чтобы потоки восстанавливались, когда нет задач для запуска.

Ответ №1:

Я полагаю, что объект-исполнитель будет собирать мусор, но я не знаю, будет ли он также отключен.

На самом деле Executors.newSingleThreadExecutor() under the wood создает FinalizableDelegatedExecutorService экземпляр, который будет вызывать shutdown finalize , указывая, что он будет автоматически отключен при сборе мусора.

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

Комментарии:

1. Есть ли у вас какие-либо ссылки на тот факт, что создается экземпляр FinalizableDelegatedExecutorService?

2. да, здесь grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…

3. @ichfarbstift код. Но этот аспект кода не гарантируется «контрактом», поэтому не зависите от него. Вызовите shutdown() , прежде чем ваша ExecutorService ссылка будет потеряна. И обратите внимание, что, несмотря shutdown() на то, что он был вызван, ExecutorService он будет выполняться до тех пор, пока не будут выполнены ранее отправленные задачи.

4. @Nicolas Это означает, что если я хочу быть уверен, что поток уничтожен в приведенном выше коде, executor должен быть экземпляром ExecutorService, и я должен вызвать executor . завершение работы () после выполнения (r2)?

5. Я видел это недавно и не знаю, какой сценарий заключается в том, что ExecutorService будет фактически завершен. Поскольку текущие потоки ссылаются на ES, похоже, что он никогда не будет завершен. Единственный способ, которым это может произойти, — это если нет активных активных потоков, тогда, я думаю, это будет завершено.

Ответ №2:

Из документации ExecutorService мы можем прочитать

«Неиспользуемый ExecutorService должен быть закрыт, чтобы разрешить восстановление его ресурсов».

В принципе, вам придется завершить службу исполнителя вручную. В то время как объект-исполнитель сам по себе будет собирать мусор, его внутренние потоки не будут.

Комментарии:

1. Созданные потоки имеют ссылку на те ExecutorService , в которых они выполняются. Пока они живы, ExecutorService они не будут иметь права на сборку.

2. @erickson Документация не обещает, что что-то конкретное произойдет, если ваш код потеряет ссылку на ExecutorService , и предупреждает вас, что вам следует закрыть его, если вы хотите, чтобы «ресурсы» были восстановлены. Если вы хотите, чтобы ваш код «запускался где угодно», то вам, вероятно, следует верить тому, что говорит javadoc, и не предполагать ничего о том, что javadoc оставляет недосказанным.

3. Давным-давно, раньше Executor , я написал довольно причудливый пул потоков, который мог определить, был ли он неправильно удален, и закрыть его рабочие; рабочие ссылались на пул, который им «принадлежал», через слабую ссылку.

Ответ №3:

Объекты могут быть GC’d, только если на этот объект не ссылается корень GC. Что такое корень GC? Наиболее распространенными являются системные классы и запущенный поток. ExecutorService будет создавать и поддерживать запущенные потоки, поэтому, даже если ES создается внутри метода, ES все равно будут доступны, а не GC’d .

Как упоминают другие, вам нужно будет выключить ES, чтобы он был GC’d.