JavaRush /Курсы /Java Multithreading /Executor, ExecutorService, Callable

Executor, ExecutorService, Callable

Java Multithreading
8 уровень , 9 лекция
Открыта
Executor, ExecutorService, Callable - 1

— Привет, Амиго!

Ничего нельзя создать идеальным с первого раза. Это касается и нитей. Со временем разработчики Java убедились, что интерфейс Runnable не идеален. Он не поддерживал перебрасывание исключений и не позволял узнать результат выполнения задачи…

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

Поэтому был придуман интерфейс Callable. Он гораздо лучше подходит для параллельного выполнения небольших задач, чем Runnable и Thread, еще и потому, что является generic-интерфейсом.

Вот типичный класс, который реализует интерфейс:

Пример
class ReverseString implements Callable<String>
{
 String str;

 ReverseString(String str)
 {
  this.str = str;
 }

 public String call() throws Exception 
 {
  StringBuilder builder = new StringBuilder(str);
  builder.reverse();
  return builder.toString();
 }
}

В отличие от Runnable, тут мы должны переопределить метод call, который возвращает результат, заданный типом-параметром. Такой подход гораздо удобнее, чем метод run интерфейса Runnable, который возвращает void. Иногда разработчикам приходилось придумывать различные «обходные пути», чтобы получить результат работы нити.

— Ясно.

— А теперь смотри, как Callable может работать в паре с ThreadPoolExecutor:

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

Вот как это работает:

Пример
//1. Создаем ThreadPoolExecutor
ExecutorService service = Executors.newFixedThreadPool(5);

//2 помещаем в него задачу для выполнения
Future<String> task = service.submit(new ReverseString("Amigo")); 

//3 ждем пока задача выполнится
while(!task.isDone()) { Thread.sleep(1); }

//4 пробуем получить результат задачи 
//получим или результат или исключение, если оно было при выполнении задачи
try { System.out.println("Развернутая строка : " + task.get()); } catch (Exception ie) { ie.printStackTrace(System.err); }

//5 останавливаем ThreadPool. 
service.shutdown();

— Круто! Особенно интерфейс Future понравился. А какие у него есть методы?

— Вот самые интересные:

Метод Описание
boolean cancel(boolean mayInterrupt);
Останавливает задачу.
boolean isCancelled();
Возвращает true, если задача была остановлена.
boolean isDone();
Возвращает true, если выполнение задачи завершено.
V get() throws InterruptedException, ExecutionException;
Возвращает результат вызова метода call или кидает исключение, если оно было.

— Круто! Так задачи еще и останавливать можно.

— Не сильно на это надейся – не каждую нить можно остановить. Но если задача еще в очереди, то это отлично сработает.

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

— Отлично. На этом сегодня и закончим.

Комментарии (61)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
13 августа 2025
Раздел с комментариями постепенно превращается в пустошь...
2 октября 2024
Алексей Уровень 7
2 мая 2025
ладно!
Andrew Karev Уровень 51
9 мая 2024
Так, что-то тут давно комментариев не было. Нужно исправлять
Kurama Уровень 50
26 ноября 2022
После того набора из 6 массивных доп лекций по потокам - это цветочки
Камушек Уровень 36
23 декабря 2023
Особенно если еще и проходить по всем вложенным ссылкам…
Kim FIame Уровень 37
16 августа 2022
Вот читаю все это и появляется вопрос - часто ли вообще нити и работа с ними встречаются в реальных задачах ? Или это нишевый функционал который нужен ровно чтобы погуглить его раз в год и забыть на оставшееся время ?
Oleg Khilko Уровень 51
30 августа 2022
Где-то тут читал что пареньку новенькому дали разделить кусок кода на потоки, он 2 что ли дня промучался и не смог это сделать. Здесь больше вопрос не в том что ты должен это знать на 100%, здесь больше вопрос что в твоем уравнении знаний по джаве есть эта переменная и она не создает для тебя "вау эффекта".
Виктор Уровень 1
3 октября 2022
Конечно часто. Особенно в задачах, где ты должен отслеживать сразу несколько вещей, например, пользовательские интерфейсы и т.д. Или некие независимые вычисления (например, проверка доступности хостов ping-ом - зачем делать по очереди, если можно одновременно).
Kurama Уровень 50
26 ноября 2022
Я написал игру тетрис. Основная нить проверяла действия пользователя (пауза, изменение счета и скорости игры, движение фигуры в пространстве нажатием клавиш и проверка "физики" объектов), доп нить отвечала за постепенное опускание фигуры (потому что перемещение фигуры по горизонтали не должно останавливать её падение), ещё одна доп нить появлялась, когда необходимо было вращать фигуру (то же самое. Перемещение, падение и вращение - это три независимых процесса, хотя можно было не давать фигуре двигаться влево и вправо, только вниз, пока та вращается, но зачем?) Хоть в игре, написанной Про, всё было бы немного иначе, но по факту в какой-нибудь крутой игре падение двух листиков - это могло бы быть двумя нитями, хотя там скорее всего "экономят" на таком, но каждый нпс - это же своеобразная нить (наверное) Джава же в основном даёт 2 пути: какие-то андроид-игры и энтерпрайз (грубо говоря), поэтому и навёл такой пример, хотя сам пойду в энтерпрайз... Даже служебные приложения - это нити. Да и, переходя на сайт, ты видишь прогруженную одной нитью картинку, пока остальные проводят расчеты "действий" на сайте. Ведь, делала бы это одна нить, твоя страница на сайте загружалась бы ооочень долго
Denis Odesskiy Уровень 47
30 мая 2024
Я для игр на java использовал libGTX, отличная штука, позволяет делать игру сразу под андроид, десктоп и web, имеет кучу инструментария (отдельно на их сайте) для тайлов, уровней, утилиту классную для создания меню (ui) и прочее. Больше чем юнити зашла, хотя местами требует больше возни (ну например с тем же игровым меню), но и гибкости у нее больше. А Вы чем пользовались? П/С. Ой, не заметил что пост аж 2022 года, наверное автор уже не читает его, а работает в каком ни-будь Гугле 😉.
Дмитрий Уровень 46
13 августа 2022
Андрей Шубный Уровень 51
5 декабря 2021
boolean cancel(boolean mayInterrupt);-останавливает задачу-странно что это все описание. В то же время для других методов описание намного подробнее, при том что они очевиднее изначально.
Kurama Уровень 50
26 ноября 2022
Та вроде более менее понятно интуитивно. boolean mayInterrupt намекает, что у нити скорее всего вызовется interrupt(), только непонятно зачем вообще передавать параметр, хотя сам делал методы, в которые передавал boolean canDoingSmth, ток не помню зачем, вроде влияло на упрощение процессов вызываемого метода Возвращаемый boolean скорее всего говорит об удачной\неудачной операции, но это неточно
Orion Уровень 31
27 ноября 2021
А зачем цикл в котором мы проверяем isDone, ужели get() и так прекрасно подождёт пока не получит что ему надо? Или это просто для примера так сделано, что бы мы знали о возможности чекать состояние задачи?
28 апреля 2022
о том же подумал.
KirilX Уровень 51
28 июля 2022
Скорее для того, чтоб дождаться результата, а потом перейти к строке №17
23 июля 2021

service.shutdown();
"Инициирует упорядоченное завершение работы, при котором ранее отправленные задачи выполняются, но новые задачи не принимаются." Видел как Алишев в видео его вызывает сразу после заполнения заданиями, и у него все работает. Говорит для запуска пула. А тут в конце вызвали... Кто прав?
Queer27 Уровень 38
14 августа 2021
Как я понял shutdown() просто запрещает добавление новых задач в очередь, но не влияет на исполнение уже находящихся в ней. А выполнение задачи как раз-таки инициирует метод submit() (внутри себя вызывает метод execute()).
SERGEY Уровень 31
17 марта 2022
Нет разницы где вызывать этот метод, все зависит от задачи. Ты перепутал методы shutdown и shutdownNow. А задачами управляет екзекьютер, который определен в тредпуле. В прошлой лекции же писали об этом.
Maks Panteleev Уровень 41
1 июня 2021
если че метод get автоматически ждет завершения работы программы)