您的位置: 首页 - 站长

WordPress简单百度站长插件做网站用的什么编程语言

当前位置: 首页 > news >正文

WordPress简单百度站长插件,做网站用的什么编程语言,江门网站seo优化,免费seo快速排名系统引言 在并发编程中#xff0c;我们经常需要处理多线程的任务#xff0c;这些任务往往具有依赖性#xff0c;异步性#xff0c;且需要在所有任务完成后获取结果。Java 8 引入了 CompletableFuture 类#xff0c;它带来了一种新的编程模式#xff0c;让我们能够以函数式编…引言 在并发编程中我们经常需要处理多线程的任务这些任务往往具有依赖性异步性且需要在所有任务完成后获取结果。Java 8 引入了 CompletableFuture 类它带来了一种新的编程模式让我们能够以函数式编程的方式处理并发任务显著提升了代码的可读性和简洁性。 在这篇博客中我们将深入探讨 CompletableFuture 的设计原理详细介绍其 API 的使用方式并通过具体的示例来展示其在并发任务处理中的应用。我们也将探讨其与 FutureCompletableFuture 以及 Java 并发包中其他工具的对比理解何时以及为什么需要使用 CompletableFuture。让我们一起踏上这个富有挑战性的学习之旅吧 ❝ 在开始之前我们先来回顾一下Java语言发展历史 ❞ Java 并发编程的演进 自从诞生以来Java 就一直致力于提供强大的并发和异步编程工具。在最初的 JDK 1.4 时期Java 开发者需要使用低级的并发控制工具如 synchronized 和 wait/notify这些工具虽然功能强大但使用起来非常复杂。 为了简化并发编程Java 在 JDK 1.5 中引入了JUC包提供了一系列高级的并发控制工具如 ExecutorService、Semaphore 和 Future。 ❝ 我们先来看下Future到底是怎么进行异步编程的 ❞ Future的异步编程之旅 在开始我们的旅程之前我们先看看一下这个需求。 一个复杂的需求 假设你正在为一家在线旅行社工作用户可以在网站上搜索并预订飞机票和酒店。以下是你需要处理的一系列操作 根据用户的搜索条件查询所有可用的飞机票对每一个飞机票查询与之匹配的可用酒店对每一个飞机票和酒店的组合计算总价格将所有的飞机票和酒店的组合按照价格排序将结果返回给用户 实现 为了实现这个需求首先我们需要创建一个 ExecutorService ExecutorService executor Executors.newFixedThreadPool(10);// 1. 查询飞机票 FutureListFlight futureFlights executor.submit(() - searchFlights(searchCondition));ListFlight flights; try {flights futureFlights.get(); } catch (InterruptedException | ExecutionException e) {// 处理异常 }// 2. 对每个飞机票查询酒店 ListFutureListHotel futureHotelsList new ArrayList(); for (Flight flight : flights) {FutureListHotel futureHotels executor.submit(() - searchHotels(flight));futureHotelsList.add(futureHotels); }ListFutureListTravelPackage futureTravelPackagesList new ArrayList(); for (FutureListHotel futureHotels : futureHotelsList) {ListHotel hotels;try {hotels futureHotels.get();} catch (InterruptedException | ExecutionException e) {// 处理异常}// 3. 对每个飞机票和酒店的组合计算总价格for (Hotel hotel : hotels) {FutureListTravelPackage futureTravelPackages executor.submit(() - calculatePrices(flight, hotel));futureTravelPackagesList.add(futureTravelPackages);} }ListTravelPackage travelPackages new ArrayList(); for (FutureListTravelPackage futureTravelPackages : futureTravelPackagesList) {try {travelPackages.addAll(futureTravelPackages.get());} catch (InterruptedException | ExecutionException e) {// 处理异常} }// 4. 将所有的旅行套餐按照价格排序 travelPackages.sort(Comparator.comparing(TravelPackage::getPrice));// 5. 返回结果 return travelPackages;需求终于做完了叹气声。此时此刻生在JDK8的你会不会感同身受呢。这还是在没有处理异常没有很多业务代码的前提下。好现在缓一下我们继续。我们可以从上面代码最直观的看到什么 ❝ 再完美的表达也敌不过一个让你直观感受的例子。接下来我们来分析一下Future的缺点。 ❞ 分析这趟Future异步编程之旅 从上面的 Future 的例子中我们可以明显看到以下几点缺点 回调地狱 Future 的实现使得我们必须在每一个 Future 完成后启动另一个 Future这使得代码看起来像是在不断嵌套回调。这种方式会使得代码难以阅读和理解特别是在涉及复杂的异步任务链时。 阻塞操作 虽然 Future.get() 可以得到任务的结果但这是一个阻塞操作它会阻止当前线程的执行直到异步操作完成。这种设计对于要实现非阻塞的异步编程来说是非常不理想的。 复杂的错误处理 在使用 Future 链式处理异步任务时如果中间某个环节出现错误错误处理的复杂性就会大大增加。你需要在每个 Future 的处理过程中都增加异常处理代码这使得代码变得更加复杂和难以维护。 无法表示任务间复杂关系 使用 Future 很难直观地表示出任务之间的依赖关系。例如你无法使用 Future 来表示某个任务需要在另外两个任务都完成后才能开始或者表示多个任务可以并行执行但是必须在一个共同的任务之前完成。这种限制使得 Future 在处理复杂的异步任务链时变得非常困难。 因此为了解决这些问题CompletableFuture 被引入了 Java 8提供了更强大和灵活的异步编程工具。 CompletableFuture的异步编程之旅 同样还是上面的例子我们来看下它的实现代码 CompletableFuture.supplyAsync(() - searchFlights()) // 1. 查询飞机票.thenCompose(flights - { // 2. 对每个飞机票查询酒店ListCompletableFutureListTravelPackage travelPackageFutures flights.stream().map(flight - CompletableFuture.supplyAsync(() - searchHotels(flight)) // 查询酒店.thenCompose(hotels - { // 3. 对每个飞机票和酒店的组合计算总价格ListCompletableFutureTravelPackage packageFutures hotels.stream().map(hotel - CompletableFuture.supplyAsync(() - new TravelPackage(flight, hotel))).collect(Collectors.toList());return CompletableFuture.allOf(packageFutures.toArray(new CompletableFuture[0])).thenApply(v - packageFutures.stream().map(CompletableFuture::join).collect(Collectors.toList()));})).collect(Collectors.toList());return CompletableFuture.allOf(travelPackageFutures.toArray(new CompletableFuture[0])).thenApply(v - travelPackageFutures.stream().flatMap(future - future.join().stream()).collect(Collectors.toList()));}).thenApply(travelPackages - { // 4. 将所有的旅行套餐按照价格排序return travelPackages.stream().sorted(Comparator.comparing(TravelPackage::getPrice)).collect(Collectors.toList());}).exceptionally(e - { // 处理所有的异常// 处理异常return null;});你可能乍一看感觉怎么比Future还要复杂。但是实际在业务中它反而更加容易读懂。每一步每一个操作都可以顺着thenCompose下去。 分析这趟CompletableFuture异步编程之旅 CompletableFuture 是 Java 8 中引入的用于解决在使用 Future 时遇到的一些问题。它实现了 Future 和 CompletionStage 接口并且提供了大量的方法来帮助你更好地控制和管理异步操作。我们来结合上面的例子来分析它的优点 链式编程 我们使用 CompletableFuture 中的 supplyAsync 方法来异步地开始查询航班的操作 CompletableFutureListFlight flightsFuture CompletableFuture.supplyAsync(() - searchFlights(source, destination));然后我们使用 thenCompose 方法将查询航班和查询酒店的操作连在一起 CompletableFutureListTravelPackage travelPackagesFuture flightsFuture.thenCompose(flights -CompletableFuture.supplyAsync(() - flights.stream().map(flight - searchHotels(flight)).collect(Collectors.toList())));非阻塞操作 上述的 thenCompose 方法是非阻塞的即查询酒店的操作会立即开始而不需要等待查询航班的操作完成。 异常处理 我们使用 exceptionally 方法处理查询航班和查询酒店过程中可能出现的异常 CompletableFutureListTravelPackage travelPackagesFuture flightsFuture.thenCompose(flights -CompletableFuture.supplyAsync(() - flights.stream().map(flight - searchHotels(flight)).collect(Collectors.toList()))).exceptionally(ex - {System.out.println(失败了: ex);return new ArrayList();});表示任务间复杂关系 我们使用 CompletableFuture.allOf 方法来表示所有的旅行套餐计算任务都必须在开始排序之前完成 CompletableFutureListTravelPackage sortedTravelPackagesFuture travelPackagesFuture.thenApply(travelPackages -travelPackages.stream().flatMap(List::stream).sorted(Comparator.comparing(TravelPackage::getPrice)).collect(Collectors.toList()));❝ 暂停一分钟再细细体会上面的例子。我们接着来集中比较这两者 ❞ CompletableFuture与Future的比较 异步执行与结果获取 Future 提供了一种在未来某个时间点获取结果的方式但它的主要问题是在获取结果时如果结果尚未准备好会导致阻塞。另外使用 isDone() 方法进行轮询也不是一个好的选择因为它将消耗CPU资源。CompletableFuture 提供了非阻塞的结果获取方法thenApply, thenAccept, thenRun 等方法可以在结果准备好后被自动执行这样我们不需要手动检查和等待结果。 链式操作 Future 不支持链式操作我们无法在 Future 完成后自动触发另一个任务。CompletableFuture 提供了 thenApply, thenAccept, thenRun, thenCompose, thenCombine 等一系列方法用于在当前任务完成后自动执行另一个任务形成任务链。 异常处理 在 Future 中只能通过 get() 方法获取异常但是这种方式会阻塞线程直到任务执行完毕。CompletableFuture 提供了 exceptionally, handle 等方法我们可以用这些方法在发生异常时提供备用的结果或者对异常进行处理。 任务组合 Future 并未提供任何任务组合的方式。CompletableFuture 提供了 allOf, anyOf, thenCombine 等方法我们可以通过这些方法来表示任务间的并行关系或者汇聚关系。 灵活的任务执行控制 Future 在任务执行上相对较为死板我们无法中途取消任务也无法在任务结束后执行特定操作。CompletableFuture 提供了 cancel, complete 等方法用于中途取消任务或者提前完成任务。此外whenComplete 和 whenCompleteAsync 方法允许我们在任务结束时无论成功或失败都可以执行特定的操作。 ❝ 假如有一个面试官现在问题它们两者的区别你会回答了吗接下来我们来解析一下 ❞ 进阶 | 理解CompletableFuture原理 为了让你理解的不那么晦涩我为你讲生活中的例子 我们可以把 CompletableFuture 想象成一家装配线生产车间。每一件零件任务的加工完成Future 完成都可能会触发下一步工作下一步的操作而每一步工作的完成都会通知车间Future以便开始下一个阶段的生产。这个过程就像一条流水线每完成一个步骤就自动进行下一个。 带着这个场景我们接着往下看。 任务链 CompletableFuture 的源码中有一个内部类 Completion代表了任务链中的一项任务。每当一个任务完成时它都会尝试去完成依赖于它的任务就像流水线上的工人完成了一部分工作后就会把半成品传递给下一个工人。 abstract static class Completion extends ForkJoinTaskVoid implements Runnable, AsynchronousCompletionTask {// … }结果容器 CompletableFuture 本身就是一个结果容器它持有了执行的结果包括正常的计算结果或者执行过程中出现的异常。 volatile Object result; // The outcome of the computation工作线程 所有的异步任务都会提交到 ForkJoinPool.commonPool() 中进行执行当然也可以指定自定义的 Executor 来执行任务。 static final ForkJoinPool ASYNC_POOL ForkJoinPool.commonPool();任务触发 当一个任务完成后CompletableFuture 会通过 tryFire 方法触发与之关联的下一个任务。这就好比工人完成了一部分工作后通知流水线的下一位工人继续完成接下来的工作。 final CompletableFutureT postFire(CompletableFuture? a, int mode) {// …if (a ! null a.stack ! null) {if (mode 0)a.cleanStack();elsea.postComplete();}if (b ! null b.stack ! null) {if (mode 0)b.cleanStack();elseb.postComplete();}return null;}是不是有点理解了呢我可以肯定的说你已经超过80%的人了 CompletableFuture的主要方法 细心的你肯定发现了CompletableFuture大多数方法都实现于一个CompletionStage接口。当然我在这里可以为你把所有方法都试过一遍但是你肯定会看的特别累。这样我把上面需求中所用到的方法都为你讲解剩下的请你结合网上的案例学习。 supplyAsync()方法 这个方法用于异步执行一个供应函数并返回一个CompletableFuture对象。在我们的示例中这个方法用于启动一个异步任务来查找航班。 CompletableFutureListFlight flightsFuture CompletableFuture.supplyAsync(() - searchFlights(destination));thenCompose()方法 这个方法用于链接多个CompletableFuture对象形成一个操作链。当一个操作完成后thenCompose()方法会将操作的结果传递给下一个操作。在我们的示例中这个方法用于在找到航班之后查找酒店。 CompletableFutureListHotel hotelsFuture flightsFuture.thenCompose(flights - CompletableFuture.supplyAsync(() - searchHotels(destination)));thenCombine()方法 这个方法用于将两个独立的CompletableFuture对象的结果合并为一个结果。在我们的示例中这个方法用于将查找航班和酒店的结果合并为一个旅行套餐。 CompletableFutureListTravelPackage travelPackagesFuture flightsFuture.thenCombine(hotelsFuture, (flights, hotels) - createTravelPackages(flights, hotels));thenAccept()方法 这个方法在CompletableFuture对象完成计算后执行一个消费函数接收计算结果作为参数不返回新的计算值。在我们的示例中这个方法用于打印出所有的旅行套餐。 travelPackagesFuture.thenAccept(travelPackages - printTravelPackages(travelPackages));allOf()方法 这个方法用于将一个CompletableFuture对象的数组组合成一个新的CompletableFuture对象这个新的CompletableFuture对象在数组中所有的CompletableFuture对象都完成时完成。在我们的示例中这个方法用于将每个航班与每个酒店的组合结果也就是旅行套餐组合在一起。 CompletableFuture.allOf(packageFutures.toArray(new CompletableFuture[0])).thenApply(v - packageFutures.stream().map(CompletableFuture::join).collect(Collectors.toList()));thenApply()方法 这个方法用于对CompletableFuture的结果进行变换并返回一个新的CompletableFuture对象。在我们的示例中这个方法用于将查询到的旅行套餐按照价格进行排序。 .thenApply(travelPackages - { // 4. 将所有的旅行套餐按照价格排序return travelPackages.stream().sorted(Comparator.comparing(TravelPackage::getPrice)).collect(Collectors.toList());})exceptionally()方法 这个方法用于处理CompletableFuture的异常情况。如果CompletableFuture的计算过程中抛出异常那么这个方法会被调用。在我们的示例中这个方法用于处理查询旅行套餐过程中可能出现的任何异常。 .exceptionally(e - { // 处理所有的异常// 处理异常return null;});❝ 当然这些方法已经够你用了。除非这个需求比我想得还复杂那算你厉害。哦不对算需求变态。现在你可以挥起历史的毛笔续写了吗 ❞ Java 并发编程的续章 JDK 1.5 的 Future 解决了许多并发编程的复杂性但是它仍有一些局限性。Future 只能描述一个异步操作并不能描述一个由多个步骤组成的异步操作。例如当需要处理一个由多个异步操作序列组成的业务流程时你可能会发现你的代码被复杂的回调逻辑淹没这就是人们常说的回调地狱。此外Future 没有提供一种有效的方式来处理异步操作的结果你只能通过阻塞调用 get() 方法来获取结果。 为了解决这些问题Java 在 JDK 1.8 中引入了 CompletableFuture。CompletableFuture 是 Future 的增强版它不仅能表示一个异步操作还可以通过 thenCompose(), thenCombine(), allOf() 等方法来描述一个由多个步骤组成的异步操作。通过这些方法CompletableFuture 能以流畅的链式调用的方式来描述复杂的异步业务流程这大大简化了异步编程的复杂性。 常见面试题 请解释一下 Future 接口在 Java 中的用途解释一下 Future 的局限性是什么请解释一下 CompletableFuture 的用途以及它如何克服 Future 的局限性如何用 CompletableFuture 来表示一组并行的异步操作请解释一下 CompletableFuture 的 thenApply()thenCompose()和 thenCombine() 方法的作用及区别如果你有一个耗时的异步操作需要执行但是你又不希望调用 get() 方法时阻塞你可以使用 CompletableFuture 的哪个方法来达到这个目的如何处理 CompletableFuture 的异常请解释一下 CompletableFuture 的工作原理 阅读完文章的你是否可以回答这些问题呢我在留言等你。 总结 好了到这里就结束了我们来回顾一下。首先我带你回顾了一下Java并发世界的编年史。紧接着我带你体验了一下古人经常使用的Future。感到它的不妙之后我带你回到CompletableFuture 。紧接着有深入了解了它的全貌以及使用方法。