Эта статья начинается с примера и представляетCompletableFuture
Базовое использование. Но сколько бы вы ни говорили, лучше потренируйтесь сами. Поэтому предлагаю вам ее прочитать, потренироваться на компьютере и быстро освоить.CompletableFuture
.
Адрес личного блога:sourl.cn/s5MbCm
Полный текст аннотации:
-
Future
VSCompletableFuture
-
CompletableFuture
Основное использование
0x00 Предисловие
В некоторых бизнес-сценариях нам необходимо использовать многопоточное асинхронное выполнение задач для ускорения выполнения задач. Java предоставляетRunnable
Future<V>
Два интерфейса используются для реализации логики асинхронной задачи.
Несмотря на то чтоFuture<V>
Результат выполнения задачи можно получить, но способ получения остается неизменным. мы должны использоватьFuture#get
Заблокируйте вызывающий поток или используйте опрос, чтобы определитьFuture#isDone
То ли задача окончена, то и получите результат.
Эти два метода обработки не очень элегантны, и библиотека параллельных классов до JDK8 не предоставляла соответствующий метод реализации асинхронного обратного вызова. Ни в коем случае, мы должны использовать сторонние библиотеки классов, такие какGuava
, расширенныйFuture
, добавьте поддержку функции обратного вызова. Соответствующий код выглядит следующим образом:
Хотя этот метод расширяет возможности асинхронного программирования Java, он по-прежнему не может решить сценарий, в котором несколько асинхронных задач должны зависеть друг от друга.
Чтобы привести пример из жизни, если нам нужно путешествовать, нам нужно выполнить три задачи:
- Задача 1: Заказать рейс
- Задача 2: Заказать гостиницу
- Задача 3: Заказать услугу аренды автомобиля
Очевидно, что задача 1 и задача 2 не связаны между собой и могут выполняться отдельно. Но задача 3 должна дождаться завершения задачи 1 и задачи 2, прежде чем заказывать услугу аренды автомобиля.
Для того, чтобы получить результаты выполнения задачи 1 и задачи 2 при выполнении задачи 3, нам также необходимо использоватьCountDownLatch
.
0x01. CompletableFuture
После JDK8 в Java был добавлен очень мощный класс:CompletableFuture
. Использование только этого класса может легко выполнить вышеуказанные требования:
Вы можете оставить это в покое
CompletableFuture
СвязанныйAPI
, о чем будет подробно рассказано ниже.
В сравненииFuture<V>
,CompletableFuture
Преимущества:
- Нет необходимости вручную выделять потоки, JDK автоматически выделяет
- Семантика кода — это понятные асинхронные вызовы цепочки задач.
- Поддержка оркестрации асинхронных задач
Как, это очень мощно? Далее, держитесь крепче, вот-вот начнется младший черный брат.
1.1 Список методов
Во-первых, давайте посмотрим на методы, предоставляемые этим классом через IDE:
Если немного посчитать, в этом классе всего более 50 методов, боже мой. . .
Но не бойтесь, маленький черный брат поможет вам подвести итоги, будет следовать ритму маленького черного брата и приведет вас к мастерству.CompletableFuture
.
Если изображение нечеткое, вы можете обратить внимание на «Общение программы» и ответить: «233», чтобы получить карту разума.
1.2 Создайте экземпляр CompletableFuture
СоздайтеCompletableFuture
Экземпляры объектов мы можем использовать следующими методами:
Первый метод создаетCompletableFuture
, это не о чем говорить. Мы сосредоточимся на следующих четырех асинхронных методах.
первые два методаrunAsync
Возвращаемые значения не поддерживаются, в то время какsupplyAsync
Может поддерживать возврат результатов.
По умолчанию эти два метода будут использовать публичныйForkJoinPool
Выполнение пула потоков, количество потоков по умолчанию в этом пуле потоков равноCPUколичество ядер.
Вы можете установить параметр JVM:-Djava.util.concurrent.ForkJoinPool.common.parallelism, чтобы установить количество потоков в пуле потоков ForkJoinPool.
Использование общего пула потоков будет иметь недостаток: как только задача будет заблокирована, это приведет к тому, что другие задачи не смогут выполниться. таксильныйРекомендуется использовать последние два метода Активно создавать пул потоков в соответствии с различными типами задач, чтобы изолировать ресурсы и избежать взаимного вмешательства.
1.3 Установите результат задачи
CompletableFuture
Предоставляет следующие методы для упреждающей установки результатов задачи.
boolean complete(T value)
boolean completeExceptionally(Throwable ex)
Первый способ, активная настройкаCompletableFuture
Результат выполнения задачи, если возвращаетсяtrue
, указывая на то, что настройка прошла успешно. если вернутьсяfalse
, настройка не удалась, так как задача была выполнена и уже есть результат выполнения.
Пример кода выглядит следующим образом:
// 执行异步任务
CompletableFuture cf = CompletableFuture.supplyAsync(() -> {
System.out.println("cf 任务执行开始");
sleep(10, TimeUnit.SECONDS);
System.out.println("cf 任务执行结束");
return "楼下小黑哥";
});
//
Executors.newSingleThreadScheduledExecutor().execute(() -> {
sleep(5, TimeUnit.SECONDS);
System.out.println("主动设置 cf 任务结果");
// 设置任务结果,由于 cf 任务未执行结束,结果返回 true
cf.complete("程序通事");
});
// 由于 cf 未执行结束,将会被阻塞。5 秒后,另外一个线程主动设置任务结果
System.out.println("get:" + cf.get());
// 等待 cf 任务执行结束
sleep(10, TimeUnit.SECONDS);
// 由于已经设置任务结果,cf 执行结束任务结果将会被抛弃
System.out.println("get:" + cf.get());
/***
* cf 任务执行开始
* 主动设置 cf 任务结果
* get:程序通事
* cf 任务执行结束
* get:程序通事
*/
Здесь следует отметить одну вещь: когда-тоcomplete
установлено успешно,CompletableFuture
Возвращаемый результат не будет изменен, даже если последующиеCompletableFuture
Выполнение задачи заканчивается.
Второй способ, дающийCompletableFuture
Установите объект исключения. Если настройка прошла успешно, если вызовget
Подождите, пока метод получит результат, он выдаст ошибку.
Пример кода выглядит следующим образом:
// 执行异步任务
CompletableFuture cf = CompletableFuture.supplyAsync(() -> {
System.out.println("cf 任务执行开始");
sleep(10, TimeUnit.SECONDS);
System.out.println("cf 任务执行结束");
return "楼下小黑哥";
});
//
Executors.newSingleThreadScheduledExecutor().execute(() -> {
sleep(5, TimeUnit.SECONDS);
System.out.println("主动设置 cf 异常");
// 设置任务结果,由于 cf 任务未执行结束,结果返回 true
cf.completeExceptionally(new RuntimeException("啊,挂了"));
});
// 由于 cf 未执行结束,前 5 秒将会被阻塞。后续程序抛出异常,结束
System.out.println("get:" + cf.get());
/***
* cf 任务执行开始
* 主动设置 cf 异常
* java.util.concurrent.ExecutionException: java.lang.RuntimeException: 啊,挂了
* ......
*/
1.4 CompletionStage
CompletableFuture
Реализовать два интерфейса соответственноFuture
иCompletionStage
.
Future
С интерфейсом все знакомы, здесь речь в основном идет оCompletionStage
.
CompletableFuture
Большинство методов исходят изCompletionStage
интерфейс, именно из-за этого интерфейса,CompletableFuture
Есть такая мощная функция.
хочу понятьCompletionStage
Интерфейс, нам нужно понять временные отношения задач в первую очередь. Мы можем разделить временные отношения задачи на следующие типы:
- отношения последовательного выполнения
- Отношения параллельного выполнения
- И отношения агрегации
- ИЛИ отношение агрегации
1.5 Отношения последовательного исполнения
Задачи выполняются последовательно, и следующая задача должна дождаться завершения предыдущей задачи, прежде чем продолжить.
CompletionStage
Существует четыре группы интерфейсов, которые могут описывать последовательные отношения, а именно:
thenApply
Метод должен передать основной параметр какFunction<T,R>
тип. Основные методы этого класса:
R apply(T t)
Таким образом, этот интерфейс примет результат, возвращенный предыдущей задачей, в качестве входного параметра, и результат будет возвращен, когда выполнение завершится.
thenAccept
Метод должен передать объект параметра какConsumer<T>
Type, основными методами этого класса являются:
void accept(T t)
возвращаемое значениеvoid
Видно, что этот метод не поддерживает возврат результатов, а должен передавать в качестве параметра результат выполнения предыдущей задачи.
thenRun
Метод должен передать объект параметра какRunnable
Type, этот класс должен быть всем знаком, метод ядра не поддерживает входящие параметры и не возвращает результаты выполнения.
thenCompose
метод иthenApply
то же, толькоthenCompose
нужно вернуть новыйCompletionStage
. Это понимание относительно абстрактно и может быть понято вместе с кодом.
метод сAsync, что означает, что он может выполняться асинхронно. В этой серии также есть перегруженные методы, которые можно передать в пользовательский пул потоков. Рисунок выше не показан, и читатели могут только просматривать API самостоятельно.
Наконец, мы показываем кодthenApply
Как пользоваться:
CompletableFuture<String> cf
= CompletableFuture.supplyAsync(() -> "hello,楼下小黑哥")// 1
.thenApply(s -> s + "@程序通事") // 2
.thenApply(String::toUpperCase); // 3
System.out.println(cf.join());
// 输出结果 HELLO,楼下小黑哥@程序通事
Этот код относительно прост, сначала мы запускаем асинхронную задачу, а затем последовательно выполняем две последующие задачи. Задача 2 должна дождаться завершения задачи 1, а задача 3 — дождаться выполнения задачи 2.
Вышеупомянутый метод, вы должны помнить
Function<T,R>
,Consumer<T>
,Runnable
Три разные, выбирайте и используйте в зависимости от сцены.
1.6 И отношения агрегации
Отношение агрегации AND означает, что следующая задача может быть выполнена только после завершения всех задач.
Как показано выше, задача C не начнет выполняться, пока не будут выполнены и задача A, и задача B.
CompletionStage
Существуют следующие интерфейсы, описывающие эту связь.
thenCombine
Основные параметры методаBiFunction
, рольFunction
то же, толькоBiFunction
может принимать два параметра иFunction
Можно принять только один параметр.
thenAcceptBoth
Основные параметры методаBiConsumer
также работает сConsumer
То же самое, но он должен принимать два параметра.
runAfterBoth
Основные параметры метода самые простые, они были введены выше и повторно вводиться не будут.
Эти три группы методов могут выполнять только две задачи И отношения агрегации.Если вам нужно выполнить несколько отношений агрегации задач, вам нужно использоватьCompletableFuture#allOf
, но здесь следует отметить, что этот метод не поддерживает возврат результатов задачи.
Пример кода, связанный с отношением агрегации И, был использован в начале, и я вставлю его сюда для вашего удобства:
1.7 Отношение агрегации ИЛИ
Существует отношение агрегации И, и, конечно же, есть отношение агрегирования ИЛИ. Отношение агрегации ИЛИ означает, что пока любая из нескольких задач завершена, следующая задача может быть выполнена следующей.
CompletionStage
Существуют следующие интерфейсы, описывающие эту связь:
Первые три группы интерфейсных методов передаются для участия в отношении агрегации И и не будут здесь подробно объясняться.
Конечно, можно использовать отношение агрегации ИЛИ.CompletableFuture#anyOf
Выполняйте несколько задач.
В следующем примере кода показано, как использоватьapplyToEither
Завершите отношение ИЛИ.
CompletableFuture<String> cf
= CompletableFuture.supplyAsync(() -> {
sleep(5, TimeUnit.SECONDS);
return "hello,楼下小黑哥";
});// 1
CompletableFuture<String> cf2 = cf.supplyAsync(() -> {
sleep(3, TimeUnit.SECONDS);
return "hello,程序通事";
});
// 执行 OR 关系
CompletableFuture<String> cf3 = cf2.applyToEither(cf, s -> s);
// 输出结果,由于 cf2 只休眠 3 秒,优先执行完毕
System.out.println(cf2.join());
// 结果:hello,程序通事
1.8 Обработка исключений
CompletableFuture
Если во время выполнения метода возникает исключение, при вызовеget
,join
Исключение выдается только при получении результата задачи.
Приведенный выше код мы показываем с помощьюtry..catch
Обработайте указанное выше исключение. Но это не очень элегантно,CompletionStage
Предоставляет несколько методов для изящной обработки исключений.
exceptionally
Используйте что-то вродеtry..catch
серединаcatch
Обработка исключений в блоках кода.
whenComplete
иhandle
метод похож наtry..catch..finanlly
серединаfinally
кодовый блок. Он будет выполнен независимо от того, возникнет ли исключение. Разница между двумя методами заключается в том, чтоhandle
Поддержка возврата результатов.
Пример кода ниже показываетhandle
использование:
CompletableFuture<Integer>
f0 = CompletableFuture.supplyAsync(() -> (7 / 0))
.thenApply(r -> r * 10)
.handle((integer, throwable) -> {
// 如果异常存在,打印异常,并且返回默认值
if (throwable != null) {
throwable.printStackTrace();
return 0;
} else {
// 如果
return integer;
}
});
System.out.println(f0.join());
/**
*java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
* .....
*
* 0
*/
0x02.Сводка
JDK8 обеспечиваетCompletableFuture
Функция очень мощная, она может организовывать асинхронные задачи, завершать последовательное выполнение, параллельное выполнение, отношения агрегации И, отношения агрегации ИЛИ.
Однако методов в этом классе слишком много, а методы еще и нужно передавать в различные функциональные интерфейсы, новички прямо запутаются, когда начнут их использовать. Здесь, чтобы помочь вам обобщить роль трех типов основных параметров
-
Function
Этот тип функционального интерфейса поддерживает как получение параметров, так и возврат значений. -
Consumer
Этот тип функции интерфейса поддерживает только прием параметров и не поддерживает возвращаемые значения. -
Runnable
Этот тип интерфейса не поддерживает прием параметров и не поддерживает возвращаемые значения.
После выяснения функции параметров функции, затем суммируйте соответствующие методы в соответствии с последовательностью, отношениями агрегации И, отношениями агрегации ИЛИ, чтобы их было легче понять.
Наконец, вставьте еще раз карту разума в начале статьи, надеюсь, она вам поможет.
0x03 Справочная документация
- Geek Time — Колонка параллельного программирования
- коло not.com/2016/02/29/…
- Woohoo. IBM.com/developer Я…
Последнее слово (пожалуйста, обратите внимание)
CompletableFuture
Я обратил на это внимание давно, я думал, что это последуетFuture
Кроме того, им очень легко пользоваться, но кто знает, как сложно его освоить. Различные методы API выглядят немного большими.
Позже я увидел Geek Time - колонку "Параллельное программирование" с использованием индуктивной классификации.CompletableFuture
Различные методы, все сразу поняли. Так что эта статья также относится к этому методу индукции.
Эта статья неделю искала информацию и разбирала ее, к счастью, сегодня она была успешно произведена.
Ради тяжелой работы, которую написал Сяо Хей, пожалуйста, обратите внимание и поставьте лайк. Не будь уверен в следующий раз, старший брат! Писать статьи очень сложно, и вам нужны положительные отзывы.
Если вам не хватает таланта и обучения, неизбежно будут ошибки.Если вы обнаружите какие-либо ошибки, пожалуйста, оставьте сообщение и укажите на это мне, и я его исправлю.
Спасибо за прочтение,Я придерживаюсь оригинала, добро пожаловать и спасибо за внимание~
Добро пожаловать, чтобы обратить внимание на мой официальный аккаунт: программа для общения, ежедневный толчок галантерейных товаров. Если вас интересует мой рекомендуемый контент, вы также можете подписаться на мой блог:studyidea.cn