Нужно ли очищать объекты Thread в Java? - PullRequest
1 голос
/ 09 октября 2019

В моем приложении Java есть Runnable, такой как:

this.runner = new Runnable({
    @Override
    public void run() {
        // do something that takes roughly 5 seconds.
    }
});

Мне нужно запускать это примерно каждые 30 секунд (хотя это может варьироваться) в отдельном потоке. Природа кода такова, что я могу запустить его и забыть о нем (успешно или неудачно). Я делаю это следующим образом в одной строке кода в моем приложении:

(new Thread(this.runner)).start()

Теперь это работает нормально. Тем не менее, мне интересно, есть ли какая-либо очистка, которую я должен делать на каждом из экземпляров потока после того, как они закончили работать? Я выполняю профилирование процессора этого приложения в VisualVM и вижу, что в течение 1 часа работы создается много потоков. Эта проблема действительна или все в порядке?

NB. Причина, по которой я запускаю new Thread вместо простого определения this.runner как Thread, заключается в том, что иногда мне нужно запускать this.runner дважды одновременно (до завершения первого вызова), и я не могу этого сделать, если я определил this.runner как Thread, поскольку один Thread объект может быть запущен снова только после завершения первоначального выполнения.

Ответы [ 2 ]

2 голосов
/ 09 октября 2019

Java-объекты, которые необходимо «очистить» или «закрыть» после использования, обычно реализуют интерфейс AutoCloseable. Это облегчает очистку, используя try-with-resources . Класс Thread не реализует AutoCloseable и не имеет методов "close" или "dispose". Таким образом, вам не нужно выполнять какую-либо явную очистку.

Однако

(new Thread(this.runner)).start()

не гарантирует немедленного начала вычисления Runnable. Возможно, вам все равно, удастся ли это сделать или не получится, но, думаю, вам все равно, работает ли он вообще. И вы можете захотеть ограничить количество этих задач, запущенных одновременно. Например, вы можете захотеть запустить только один. Таким образом, вы можете захотеть join() потока (или, возможно, присоединиться с таймаутом ). Присоединение к потоку гарантирует, что поток завершит свои вычисления. Присоединение к потоку с таймаутом увеличивает вероятность того, что поток начнет свое вычисление (потому что текущий поток будет приостановлен, освобождая процессор, который может запустить другой поток).

Однако, создание нескольких потоков для выполнения обычных иличастые задачи не рекомендуется. Вместо этого вам следует отправить задач в пул потоков . Это позволит вам контролировать максимальный объем параллелизма и может предоставить вам другие преимущества (например, приоритизацию различных задач), а также амортизирует затраты на создание потоков .

. Вы можете настроитьпул потоков, чтобы использовать очередь задач фиксированной длины ( bounded ) и заставить отправлять потоки в самостоятельно выполнять отправленные задачи , когда очередь заполнена. Этим вы можете гарантировать, что задачи, переданные в пул потоков, (в конечном итоге) будут выполнены. Документация ThreadPool.execute(Runnable) гласит:

Выполняет заданную задачу когда-нибудь в будущем

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

1 голос
/ 09 октября 2019

Я рекомендую вам взглянуть на Concurrency API. Существует множество предопределенных методов общего пользования. Используя ExecutorService, вы можете вызвать метод завершения работы после отправки задач исполнителю, который прекращает принимать новые задачи, ожидает выполнения ранее отправленных задач и затем завершает работу исполнителя. Для краткого вступления: https://www.baeldung.com/java-executor-service-tutorial

...