Пусть в мире не будет сложной Java для изучения
Нравится, Следуй, Избранное
Введение
- Многопоточное программирование является обычным явлением в Java-разработке.С самого начала Thread, Runnable to Future и затем CompletableFuture JDK использует многопоточность для постоянного расширения функций для нас.
- О CompletableFuture написано много вводных статей и руководств, так зачем писать эту статью? Существует довольно много руководств, но много копий и вставок или нагромождений API. Смотреть на это полностью сложно.
- Следовательно, эта статья в основном рассказывает о полноценном выравнивании с точки зрения вашего собственного обучения и расширяет полномочия из трех основных линий, чтобы вы могли понять завершительную культуру с четкого уровня.
2. Механизм «Начало из будущего»
-
Механизм Future был представлен в Java 1.5 и представляет собой результат асинхронных вычислений. О Future/Callable можно обратиться к
nuggets.capable/post/684490…, чтобы у вас сразу появилось чувство иерархии. Не все, но кажется довольно запутанным.
-
Future решает проблему, заключающуюся в том, что Runnable не имеет возвращаемого значения, и предоставляет два вида get() для получения результата.
public interface Future<V>{
//堵塞获取
V get() throws InterruptedException,ExecutionException;
//等待timeout获取
V get(long timeout,TimeUnit unit) throws InterruptedException,ExecutionException,TimeoutException;
}
3. Полное будущее родился
- Метод блокировки получения результатов явно противоречит асинхронному программированию, метод опроса по тайм-ауту не элегантен и не позволяет вовремя получить результаты вычислений. Многие языки предоставляют обратные вызовы для асинхронного программирования, например Node.js. Некоторые библиотеки классов Java, такие как netty, guava и т. д., также расширяют Future, чтобы улучшить возможности асинхронного программирования. Официальная явно не отстает: в Java 8 добавлены CompleteFuture и связанные с ним API, что значительно расширяет возможности Future.
//接受Runnable,无返回值,使用ForkJoinPool.commonPool()线程池
public static CompletableFuture<Void> runAsync(Runnable runnable)
//接受Runnable,无返回值,使用指定的executor线程池
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
//接受Supplier,返回U,使用ForkJoinPool.commonPool()线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
//接受Supplier,返回U,使用指定的executor线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
- Мы видим, как CompleteFuture достигает интерфейсов Future, CompletionStage2. Будущее, которое мы все знаем, в основном используется для реализации асинхронного события, которое не должно запускаться.
3.1 Создайте новый CompletableFuture
-
runAsync не возвращает значения
-
SupplyAsync имеет возвращаемое значение
3.2. Стадия завершения
-
Сцена значит сцена. Как следует из названия, CompletionStage представляет собой этап синхронного или асинхронного вычисления и ссылку на конечный результат. Несколько этапов завершения образуют сборочную линию, и сборка одного звена может быть передана следующему звену. Результату может потребоваться пройти через несколько этапов завершения.
-
Например, в очень распространенном сценарии обмена сначала списываются баллы, затем отправляется текстовое сообщение, а затем устанавливается логотип персональной домашней страницы. .
-
CompletionStage обеспечивает поддержку последовательного вызова CompletableFuture, а thenApply().thenApply()... CompletionStage связывается один за другим.
-
Simple CompletionStage: после выполнения асинхронной задачи SupplyAsync() используйте thenApply() для передачи результата на следующий этап.
Четыре, три угла для анализа CompletableFuture
- С введением двух предварительных концепций CompletableFuture и CompletionStage мы можем формально понять CompletableFuture с трех точек зрения.
4.1 Последовательные отношения
- thenApply
//这是最简单也是最常用的一个方法,CompletableFuture的链式调用
public static void main(String[] args) {
CompletableFuture<String> completableFuture = CompletableFuture.runAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3);
System.out.println("hello");
}catch (Exception e){
e.printStackTrace();
}
}).thenApply(s1 -> {
System.out.println(" big");
return s1 + "big";
}).thenApply(s2 -> " world");
}
//hello big world
-
thenRun
- Когда вычисление завершено, выполняется Runnable, а результат вычисления CompletableFuture не используется.Предыдущий результат вычисления CompletableFuture также будет проигнорирован, и будет возвращен тип CompletableFuture.
-
thenAccept
- thenApply и thenAccept похожи, разница в том, что thenAccept является чистым потреблением, не имеет возвращаемого значения и поддерживает цепочку вызовов.
CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(5);
return "success";
} catch (Exception e) {
e.printStackTrace();
return "error";
}
}).thenAcceptAsync(s->{
if ("success".equals(s)){
System.out.println(s);
}else {
System.err.println(s);
}
});
- thenCompose
- Оба принимают функцию, входные данные — вычисленное значение текущего CompleteableFuture и возвращают новый CompletableFuture. То есть этот новый CompleteableFuture объединяет исходный CompleteableFuture с CompleteableFuture, возвращаемым функцией.
- Обычно используется, когда второй CompleteableFuture должен использовать результат первого CompleteableFuture в качестве входных данных.
public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn)
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor)
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 1)
.thenCompose(x -> CompletableFuture.supplyAsync(() -> x+1));
thenApply、thenCompose都接受一个Function的函数式接口,那么区别呢? 1.thenApply使用在同步mapping方法。 2.thenCompose使用在异步mapping方法。
- 🌰 вот и мы
//thenApply
thenApply(Function<? super T,? extends U> fn)
//thenCompose
thenCompose(Function<? super T,? extends CompletableFuture<U>> fn)
//可以看出thenApply返回的是一个对象U,而thenCompose返回的是CompletableFuture<U>
//从使用角度是来看,如果你第二个操作也是异步操作那么使用thenCompose,如果是一个简单同步操作,那么使用thenApply,相信实战几次你就能明白什么时候使用thenApply、thenCompose。
4.2, И отношения
-
thenCombine
- Судя по моему уровню 6, «комбинировать» и «компоновать», похоже, имеют значение «комбинировать» и «комбинировать», так в чем же разница?
- Основное отличие состоит в том, что связывание двух полномочий Fenchombine не зависит от зависимостей, а второе рейтинговое завершение.
- Многократное завершение комбинации 1ncombine является независимым, но весь конвейер синхронизирован.
🌰 вот и мы
//从上图可以看出,thenCombine的2个CompletableFuture不是依赖关系,第二个CompletableFuture比第一个CompletableFuture先执行,最后的BiFunction()组合2个CompletableFuture结果。
//再次强调:整个流水线是同步的
- thenAcceptBoth
//2个CompletableFuture处理完成后,将结果进行消费。
//与thenCombine类似,第2个CompletableFuture不依赖第1个CompletableFuture执行完成,返回值Void。
- runAfterBoth
- После завершения двух CompletableFuture будет выполнен Runnable. Это похоже на thenAcceptBoth и thenCombine, но разница в том, что runAfterBoth не заботится о возвращаемом значении любого CompletableFuture, пока CompletableFuture выполняется, он будет работать, и он также не имеет возвращаемого значения.
- allOf
- Просто дождитесь завершения всех CompletableFuture и верните CompletableFuture.
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("i am sleep 1");
} catch (Exception e) {
e.printStackTrace();
}
return "service 1";
});
CompletableFuture<String> completableFuture2 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
System.out.println("i am sleep 2");
} catch (Exception e) {
e.printStackTrace();
}
return "service 2";
});
CompletableFuture<String> completableFuture3 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3);
System.out.println("i am sleep 3");
} catch (Exception e) {
e.printStackTrace();
}
return "service 3";
});
CompletableFuture<Void> completableFuture = CompletableFuture
.allOf(completableFuture1, completableFuture2, completableFuture3);
completableFuture.join();
System.out.println(System.currentTimeMillis() - start);
}
4.3, отношение ИЛИ
- applyToEither
- Результат самого быстрого выполнения CompletableFuture используется как входной результат следующего этапа.
- acceptEither
- Когда завершится самое быстрое выполнение CompletableFuture, будет выполнено потребление действия.
- runAfterEither
- После завершения любого CompletableFuture будет выполнен следующий Runnable.
- anyOf
- Функция AnyOf возвращает значение после завершения любого CompletableFuture.
резюме
- CompletableFuture значительно расширяет возможности Future и упрощает асинхронное программирование.
- В этой статье в основном рассматриваются этапы между CompletableFutures с точки зрения И, ИЛИ и сериализации. Разные сцены должны накладываться на разные этапы.