Класс, реализующий Runnable, считается «выполняемой задачей» для ExecutorServices? - PullRequest
1 голос
/ 09 мая 2020

Я пытаюсь использовать Executors вместо синхронизированных методов для управления потоками для меня. Но метод submit принимает Runnable task, а не Runnable target, что мне и нужно, поскольку я запускаю один поток, в котором будет создан и запущен целевой класс, например:

        thread = new Thread(this, "thread-process");
        thread.start();

Я пытался сделать что-то эквивалентное с исполнителями:

        this.exec = Executors.newSingleThreadExecutor();
        this.exec.submit(this);

Кажется, поток запускается и работает нормально, насколько я могу судить, но я не совсем уверен, это эквиваленты? Должен ли я таким образом иметь дело с работающими целевыми потоками при использовании Executors?

1 Ответ

2 голосов
/ 09 мая 2020

tl; dr

  • Да, два подхода достигли sh одного и того же конца: некоторый код выполняется в фоновом потоке.
  • Используйте второй ( Executors framework), а не явное создание Thread.
  • Не зацикливайтесь на имени переменной, содержащей ссылку на ваш объект Runnable.

Подробности

Да, учитывая Runnable (объект с методом run), например:

public class ReportRunnable implements Runnable {

    public void run() {
        System.out.println( "Reporting at " + Instant.now() );  // Passing: ( Runnable target , String name ).
    }

}

… затем делаем следующее:

Runnable runnable = new ReportRunnable() ;
thread = new Thread( runnable , "thread-process" );
thread.start();

… фактически то же самое, что и следующее:

ExecutorService executorService = Executors.newSingleThreadExecutor() ;
… // You should be keeping a reference to the executor service, so that you can later shut it down gracefully.
Runnable runnable = new ReportRunnable() ;
executorService.submit( runnable ) ;

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

Поймите, что структура Executors (см. Учебник от Oracle) была изобретена, чтобы облегчить большинство программистов в большинстве случаев ios от необходимости овладеть тонким искусством управления потоками. Таким образом, вам редко нужно создавать экземпляр Thread самостоятельно. По возможности используйте среду исполнителя.

Одно отличие состоит в том, что метод submit службы исполнителя возвращает объект Future. В нашем коде выше мы игнорируем этот возвращенный объект. Но вы можете захотеть зафиксировать ссылку на этот объект, чтобы позже проконсультироваться о ходе выполнения или статусе завершения задачи.

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

ExecutorService executorService = Executors.newFixedThreadPool​( 3 )

;

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

ScheduledExecutorService ses = newSingleThreadScheduledExecutor() ;
… // You should be keeping a reference to the executor service, so that you can later shut it down gracefully.
Runnable runnable = new ReportRunnable() ;
ScheduledFuture<?> reportFuture = scheduler.scheduleAtFixedRate( runnable , 0 , 2 , TimeUnit.HOURS ) ;

Еще одним отличием является управление завершением потока, которое обсуждается ниже.

Имена переменных не имеют значения

Вы сказали:

Но Метод submit принимает задачу Runnable, а не цель Runnable

Кажется, вы зациклились на именовании переменных. Имена переменных здесь не важны. . Конструктор Thread Javado c использует target, как видно из моего комментария в моем методе run. Тем не менее, я выбрал go с переменной с именем runnable. Вы можете выбрать имя, например exportQuarterlySalesDataRunnable, task, target или pinkElephant.

Завершение потоков

Имейте в виду, что в конечном итоге вам нужно завершить поток (-ы). Во время выполнения вашего приложения вам может больше не понадобиться поток или выполняемая в настоящее время работа. Или ваше приложение может завершать свое выполнение, и в этом случае вы должны закрыть свои потоки или рискнуть, что они продолжат запускать zomb ie-like после остановки вашего приложения.

Служба исполнителя упрощает завершение потока, парой методов shutdown…. Вы можете прервать любую текущую работу или дождаться ее завершения.

Лямбда-синтаксис

Для полноты я упомяну, что вы можете использовать более короткий синтаксис с помощью функций лямбда, добавленных в современные Java.


Обязательный совет : Прочтите, перечитайте и еще раз прочитайте превосходную книгу Java Параллелизм на практике Брайана Гетца и др.

...