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

「Java」《深入解析Java多线程编程利器:CompletableFuture》

《深入解析Java多线程编程利器:CompletableFuture》

  • 一、 引言
    • 1. 对多线程编程的需求和挑战的介绍
    • 2. 介绍CompletableFuture的作用和优势
  • 二. CompletableFuture简介
    • 1. CompletableFuture是Java中提供的一个强大的多线程编程工具
    • 2. 与传统的Thread和Runnable相比的优点
  • 三、基本用法
    • 1.创建CompletableFuture对象的方式
    • 2. 异步执行任务并返回结果
    • 3. 使用回调函数处理异步任务的结果
  • 四、组合多个CompletableFuture
    • 1. thenCompose()方法的使用
    • 2. thenCombine()方法的使用
    • 3. allOf()和anyOf()方法的使用
  • 五、异常处理
    • 1. exceptionally()方法的使用
    • 2. handle()方法的使用
  • 六、 CompletableFuture的进阶功能
    • 1. CompletableFuture的取消和超时处理
    • 2. CompletableFuture的并发限制
    • 3. CompletableFuture与Stream的结合使用
  • 七、 示例和案例分析
    • 1. 使用CompletableFuture实现并发下载
    • 2. 使用CompletableFuture优化订单处理流程
  • 八、总结
    • 1. 重点总结CompletableFuture的核心概念和用法
    • 2. 强调CompletableFuture在多线程编程中的价值和应用场景

一、 引言

1. 对多线程编程的需求和挑战的介绍

多线程编程是指在一个程序中同时执行多个线程来提高系统的并发性和响应性。在现代计算机系统中,多线程编程已经成为开发者日常工作的一部分。以下是对多线程编程需求和挑战的介绍:

  1. 需求:
    • 提高系统的性能:通过同时执行多个线程,可以利用多核处理器的优势,实现任务的并行执行,从而提高系统的处理速度和吞吐量。
    • 改善用户体验:多线程编程可以使图形界面或交互式应用程序更加流畅和响应,避免长时间的等待和阻塞。
    • 实现后台任务:多线程可以用于执行后台任务,如数据加载、网络通信、文件写入等,提高用户界面的反应速度,同时保持后台任务的进行。
  1. 挑战:
  • 线程同步与竞态条件:多个线程共享同一份资源时,可能会引发问题,如竞态条件、死锁和数据不一致等。需要合理地使用锁、同步机制和线程安全的数据结构来保证线程之间的正确协作。
  • 上下文切换开销:在多线程环境下,线程的调度和切换会带来一定的开销,影响系统性能。合理控制线程数量和避免过度的上下文切换是关键。
  • 调试和测试困难:多线程程序的调试和测试相对复杂,由于线程间的异步执行和并发性,可能会导致问题不易重现和定位。
  • 安全性和可靠性:多线程编程需要考虑并发访问共享资源的问题,如果处理不当,可能会导致数据不一致、内存泄漏等安全问题。同时还需保证线程的稳定性、可靠性和正确性。

了解这些需求和挑战对于进行有效的多线程编程至关重要。开发者需要熟悉并掌握多线程编程的基本概念、技术和最佳实践,以解决并发编程中的问题,并正确地利用多线程来满足系统的需求。

2. 介绍CompletableFuture的作用和优势

CompletableFuture是Java 8引入的一个强大的多线程编程工具,用于处理异步任务和并发编程。它提供了更简洁、灵活和易用的方式来处理并发操作。以下是CompletableFuture的作用和优势的介绍:

  1. 异步任务处理:CompletableFuture可以用于执行异步任务,并在任务完成时获取结果。它可以帮助开发者更方便地处理耗时的操作,避免阻塞主线程。

  2. 组合多个任务:CompletableFuture可以将多个异步任务进行链式组合,实现任务之间的顺序关系。通过一系列的方法调用,可以实现任务的串行执行、并行执行以及任务间的依赖关系。

  3. 回调函数处理:CompletableFuture支持回调函数的方式处理异步任务的结果。可以在任务完成后执行相应的回调函数,进行后续操作,例如数据处理、结果分析等。

  4. 异常处理:CompletableFuture提供了灵活的异常处理机制。可以使用exceptionally()方法或handle()方法来处理任务中的异常情况,保证程序的健壮性和稳定性。

  5. 取消和超时处理:CompletableFuture支持任务的取消和超时处理。可以设置任务的执行时间上限,如果任务无法在规定时间内完成,可以进行相应的处理操作,避免长时间的等待和占用资源。

  6. 并发限制:CompletableFuture允许开发者设置任务的并发限制,控制同时执行的任务数量。这对于任务有资源限制或对并发度有要求的场景非常有用。

  7. 整合Stream操作:CompletableFuture可以与Java 8中引入的Stream API进行无缝整合。通过CompletableFuture的一些方法,可以在流中实现并行操作,提高处理效率。

CompletableFuture作为Java多线程编程的利器,使得异步任务和并发编程变得更加直观和简单。它提供了丰富的方法来处理并发操作,并具有灵活的异常处理、任务组合和回调处理能力。使用CompletableFuture可以大大简化多线程编程的复杂性,提高开发效率和程序性能。

二. CompletableFuture简介

1. CompletableFuture是Java中提供的一个强大的多线程编程工具

CompletableFuture是Java中提供的一个强大的多线程编程工具。它位于java.util.concurrent包下,是Java 8引入的一种Future的扩展形式,用于处理异步任务和并发编程。

CompletableFuture提供了一种更简洁、灵活和易用的方式来处理异步任务。它支持链式调用和函数式编程的风格,使得编写异步代码变得更加直观和方便。

通过CompletableFuture,可以完成以下操作:

  1. 异步执行:使用supplyAsync()runAsync()方法可以将任务提交到线程池中异步执行,这样就不会阻塞主线程。

  2. 链式操作:通过一系列的方法调用,可以将多个CompletableFuture组合在一起,形成一个任务链。例如,使用thenApply()thenAccept()thenCompose()等方法可以定义任务之间的依赖关系和后续操作。

  3. 异常处理:CompletableFuture提供了异常处理的机制,可以使用exceptionally()handle()whenComplete()等方法来处理异常情况,并在任务完成时执行相应的操作。

  4. 合并多个任务:使用allOf()anyOf()join()等方法可以将多个CompletableFuture进行合并和组合,实现对多个任务结果的处理。

  5. 取消和超时处理:CompletableFuture支持取消任务和设置超时时间,并提供了相应的方法来处理任务的取消和超时情况。

  6. 并发限制:可以使用CompletableFuture.supplyAsync().thenCombine()等方法来控制并发度,限制同时执行的任务数量。

CompletableFuture的引入大大简化了Java中的异步编程和并发处理,使得多线程编程变得更加方便和高效。它提供了丰富的操作方法和异常处理机制,帮助开发者更好地控制和组合异步任务,实现高效的并发编程。

2. 与传统的Thread和Runnable相比的优点

相对于传统的Thread和Runnable,CompletableFuture具有以下几个优点:

  1. 异步编程简单:CompletableFuture通过方法链的方式让异步编程变得更加直观和易于理解。开发者可以通过一系列的方法调用来组合和处理异步任务,而不需要手动管理线程和同步。

  2. 高级的任务组合:CompletableFuture提供了丰富的方法来组合多个任务,例如在一个任务完成后执行下一个任务、组合多个任务的结果等。这种链式调用的方式使得任务之间的关系更加清晰和灵活。

  3. 异常处理方便:CompletableFuture提供了专门的方法来处理异常情况。通过exceptionally()handle()whenComplete()等方法,可以更容易地捕获和处理任务中出现的异常。

  4. 取消和超时处理:CompletableFuture支持任务的取消和设置超时时间。可以使用cancel()方法取消任务,或者使用completeOnTimeout()方法设置任务的超时时间。这些功能在处理需要限时操作或在某些条件下需要中止任务的场景非常有用。

  5. 非阻塞主线程:CompletableFuture的任务是在一个线程池中执行的,因此不会阻塞主线程。这允许主线程继续执行其他操作,提高了应用程序的响应性能。

  6. 并发度控制:CompletableFuture提供了方式来控制任务的并发度。可以使用thenComposeAsync()thenCombineAsync()等方法来指定异步任务在多个线程上并发执行,从而提高性能。

  7. 整合Stream API:CompletableFuture可以与Java 8中引入的Stream API无缝集成。这意味着可以在流中使用CompletableFuture来进行并行操作,进一步简化了代码的编写和处理。

总的来说,CompletableFuture相对于传统的Thread和Runnable提供了更高级、更灵活、更易于使用的异步编程解决方案。它让异步任务的编写和组合变得更加简单和直观,并提供了丰富的方法来处理异常、取消任务和控制并发度。这使得开发者能够更好地管理和利用多线程环境,提高应用程序的性能和可维护性。

三、基本用法

1.创建CompletableFuture对象的方式

创建CompletableFuture对象的方式有多种,可以根据实际需求选择适合的方式。以下是几种常见的创建CompletableFuture对象的方式:

  1. 使用CompletableFuture.supplyAsync()创建异步执行的CompletableFuture对象,该方法接收一个Supplier类型的参数,表示要执行的任务,并返回一个CompletableFuture对象。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {// 异步执行的任务逻辑return "Hello, CompletableFuture!";
});
  1. 使用CompletableFuture.runAsync()创建异步执行的CompletableFuture对象,该方法接收一个Runnable类型的参数,表示要执行的任务,并返回一个CompletableFuture对象。
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {// 异步执行的任务逻辑System.out.println("Hello, CompletableFuture!");
});
  1. 使用CompletableFuture.completedFuture()创建已完成的CompletableFuture对象,该方法接收一个数值、对象或null作为参数,返回一个已经完成的CompletableFuture对象。
CompletableFuture<String> completedFuture = CompletableFuture.completedFuture("Hello");
  1. 使用CompletableFuture.newIncompleteFuture()创建一个未完成的CompletableFuture对象,以后可以通过调用其它方法来完成该对象。
CompletableFuture<String> future = new CompletableFuture<>();
// 后续在适当的时机通过调用complete方法完成该CompletableFuture对象
future.complete("Hello, CompletableFuture!");
  1. 使用CompletableFuture.allOf()CompletableFuture.anyOf()静态方法创建组合的CompletableFuture对象。allOf()接收多个CompletableFuture对象作为参数,并返回一个新的CompletableFuture对象,该对象在所有输入的CompletableFuture对象都完成后才会完成。anyOf()类似,只要有任意一个输入的CompletableFuture对象完成,返回的对象就会完成。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "CompletableFuture");CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2);
CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2);

这些是创建CompletableFuture对象的常见方式,根据具体的业务需求和场景,可以选择适合的方式来创建和组合CompletableFuture对象,实现异步编程和并发处理。

2. 异步执行任务并返回结果

要异步执行任务并返回结果,可以使用CompletableFuture.supplyAsync()方法创建一个CompletableFuture对象,并将要执行的任务逻辑包装在一个Supplier函数中。这个Supplier函数会在异步执行的线程中被调用,并返回计算的结果。

以下是一个示例代码:

import java.util.concurrent.CompletableFuture;public class AsyncTaskExample {public static void main(String[] args) {// 异步执行任务CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {// 异步执行的任务逻辑return "Hello, CompletableFuture!";});// 当任务完成时获取结果future.thenAccept(result -> System.out.println("Result: " + result));// 阻塞主线程,使异步任务有足够的时间完成try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}
}

在上面的示例中,我们使用CompletableFuture.supplyAsync()方法创建了一个CompletableFuture对象,并在Supplier函数中定义了要异步执行的任务逻辑。通过thenAccept()方法,我们注册了一个回调函数,当任务完成时会获取到计算的结果,并打印输出。

需要注意的是,在这个示例中,我们使用Thread.sleep()方法阻塞了主线程一段时间,以确保异步任务有足够的时间完成。实际使用中,主线程可能会执行其他的操作,而不必主动等待异步任务完成。

当然,CompletableFuture还提供了许多其他的方法来处理异步任务的结果,例如使用thenApply()方法对结果进行转换,使用exceptionally()方法处理异常情况等。根据具体的需求,可以选择适合的方法来处理异步任务的结果。

3. 使用回调函数处理异步任务的结果

使用回调函数处理异步任务的结果是通过在CompletableFuture对象上注册回调函数来实现的。当异步任务完成时,回调函数会被执行,并传递任务的结果作为参数。

以下是一个示例代码,演示如何使用回调函数处理异步任务的结果:

import java.util.concurrent.CompletableFuture;public class AsyncCallbackExample {public static void main(String[] args) {// 异步执行任务CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {// 异步执行的任务逻辑return "Hello, CompletableFuture!";});// 注册回调函数处理任务结果future.thenAccept(result -> System.out.println("Result: " + result));// 阻塞主线程,使异步任务有足够的时间完成try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}
}

在上面的示例中,我们通过thenAccept()方法在CompletableFuture对象上注册了一个回调函数。当异步任务完成后,回调函数会被执行,并将任务的结果作为参数传递给回调函数。在这个示例中,回调函数只简单地打印出结果。

需要注意的是,回调函数会在异步任务完成的线程上执行。如果回调函数需要进行耗时的操作或者阻塞,可能会影响到其他任务的执行。因此,建议在回调函数中只处理轻量级的操作,避免阻塞或耗时的操作。

除了thenAccept()方法外,CompletableFuture还提供了其他的回调函数方法,如thenApply()用于对任务结果进行转换,exceptionally()用于处理异常情况等。根据需求,选择适合的回调函数方法来处理异步任务的结果。

四、组合多个CompletableFuture

1. thenCompose()方法的使用

thenCompose()方法是CompletableFuture类提供的一个方法,用于处理异步任务的结果。它接受一个Function参数,该函数将当前CompletableFuture的结果作为输入,并返回另一个CompletableFuture对象。这个返回的CompletableFuture对象表示一个新的异步任务,可以继续执行链式操作。

下面是使用thenCompose()方法的示例代码:

import java.util.concurrent.CompletableFuture;public class ThenComposeExample {public static void main(String[] args) {// 异步执行第一个任务CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {// 第一个任务逻辑return "Hello";});// 使用thenCompose()方法处理第一个任务的结果,并执行第二个任务CompletableFuture<String> future2 = future1.thenCompose(result -> {// 第二个任务逻辑,基于第一个任务的结果return CompletableFuture.supplyAsync(() -> result + ", CompletableFuture!");});// 当第二个任务完成时获取结果future2.thenAccept(result -> System.out.println("Result: " + result));// 阻塞主线程,使异步任务有足够的时间完成try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}
}

在上面的示例中,我们首先使用CompletableFuture.supplyAsync()方法创建了一个异步任务future1,它简单地返回字符串"Hello"。接着,我们使用thenCompose()方法处理future1的结果,根据第一个任务的结果执行第二个任务。第二个任务通过CompletableFuture.supplyAsync()方法创建,它会将第一个任务的结果与字符串", CompletableFuture!"拼接在一起。

最后,我们使用thenAccept()方法注册了一个回调函数,在第二个任务完成时打印结果。

需要注意的是,thenCompose()方法返回的是一个新的CompletableFuture对象,表示一个新的异步任务。通过这种方式,可以方便地链式执行多个异步任务,每个任务都依赖于上一个任务的结果。

在实际应用中,可以根据具体需求来组合和处理异步任务的结果,使用thenCompose()方法来进行任务的串联和组合。

2. thenCombine()方法的使用

thenCombine()方法是CompletableFuture类提供的一个方法,用于将两个独立的异步任务的结果进行合并处理。它接受两个CompletionStage参数和一个BiFunction参数,该函数将两个任务的结果作为输入,并返回一个新的结果。

下面是使用thenCombine()方法的示例代码:

import java.util.concurrent.CompletableFuture;public class ThenCombineExample {public static void main(String[] args) {// 异步执行第一个任务CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {// 第一个任务逻辑return "Hello";});// 异步执行第二个任务CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {// 第二个任务逻辑return "CompletableFuture!";});// 使用thenCombine()方法处理两个任务的结果CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {// 合并处理两个任务的结果return result1 + ", " + result2;});// 当合并任务完成时获取结果combinedFuture.thenAccept(result -> System.out.println("Result: " + result));// 阻塞主线程,使异步任务有足够的时间完成try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}
}

在上面的示例中,我们首先分别创建了两个独立的异步任务future1future2,它们分别返回字符串"Hello"和"CompletableFuture!"。然后,我们使用thenCombine()方法将这两个任务的结果进行合并处理。合并的逻辑由BiFunction参数指定,它将两个任务的结果拼接起来。

最后,使用thenAccept()方法注册了一个回调函数,在合并任务完成时打印结果。

需要注意的是,thenCombine()方法返回的是一个新的CompletableFuture对象,表示一个新的异步任务。通过这种方式,可以将多个独立的异步任务的结果合并在一起,并进行后续的处理。

在实际应用中,可以根据具体需求选择使用thenCombine()方法来处理多个异步任务的结果的合并操作。

3. allOf()和anyOf()方法的使用

allOf()anyOf()方法都是CompletableFuture类提供的静态方法,用于处理多个异步任务的结果。

allOf()方法接受一个可变参数,表示一组CompletableFuture对象,返回一个新的CompletableFuture对象。这个新的CompletableFuture对象表示一个新的异步任务,当所有输入的任务都完成时,它将完成。

下面是使用allOf()方法的示例代码:

import java.util.concurrent.CompletableFuture;public class AllOfExample {public static void main(String[] args) {// 定义一组异步任务CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Task 1");CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Task 2");CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "Task 3");// 使用allOf()方法等待所有任务完成CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);// 当所有任务完成时执行回调函数allFutures.thenRun(() -> System.out.println("All tasks completed."));// 阻塞主线程,使异步任务有足够的时间完成try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}
}

在上面的示例中,我们定义了三个异步任务future1future2future3,它们分别返回字符串"Task 1"、“Task 2"和"Task 3”。然后,我们使用allOf()方法等待所有任务完成,并返回一个CompletableFuture<Void>对象。我们可以通过这个对象注册一个回调函数,在所有任务完成时打印一条消息。

需要注意的是,allOf()方法返回的CompletableFuture对象不关心每个任务的具体结果,只关心所有任务的完成情况。

anyOf()方法接受一个可变参数,表示一组CompletableFuture对象,返回一个新的CompletableFuture对象。这个新的CompletableFuture对象表示一个新的异步任务,当任意一个输入的任务完成时,它将完成。

下面是使用anyOf()方法的示例代码:

import java.util.concurrent.CompletableFuture;public class AnyOfExample {public static void main(String[] args) {// 定义一组异步任务CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Task 1");CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Task 2");CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "Task 3");// 使用anyOf()方法等待任意一个任务完成CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2, future3);// 当任意一个任务完成时执行回调函数anyFuture.thenAccept(result -> System.out.println("One task completed: " + result));// 阻塞主线程,使异步任务有足够的时间完成try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}
}

在上面的示例中,我们同样定义了三个异步任务future1future2future3,它们分别返回字符串"Task 1"、“Task 2"和"Task 3”。然后,我们使用anyOf()方法等待任意一个任务完成,并返回一个CompletableFuture<Object>对象。我们可以通过这个对象注册一个回调函数,在任意一个任务完成时打印其结果。

需要注意的是,anyOf()方法返回的CompletableFuture对象只会关注第一个完成的任务,不会等待其他任务的完成。

通过使用allOf()anyOf()方法,可以方便地处理多个异步任务的结果,并根据不同的需求进行相应的处理。

五、异常处理

1. exceptionally()方法的使用

exceptionally() 方法是 CompletableFuture 类提供的一个方法,它允许你在异步任务抛出异常时提供一个默认的返回值或进行异常处理。该方法接受一个函数作为参数,这个函数会在异步任务抛出异常时被调用。

下面是 exceptionally() 方法的使用示例:

import java.util.concurrent.CompletableFuture;public class ExceptionallyExample {public static void main(String[] args) {// 定义一个异步任务CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {// 任务逻辑,这里会抛出异常throw new RuntimeException("Task failed!");});// 使用 exceptionally() 方法处理异步任务的异常CompletableFuture<Integer> result = future.exceptionally(ex -> {// 在异常发生时处理异常并提供默认返回值System.out.println("Exception occurred: " + ex.getMessage());return 0;});// 等待异步任务完成并获取最终结果int value = result.join();System.out.println("Result: " + value);}
}

在上面的示例中,我们定义了一个异步任务 future,它会抛出一个运行时异常。然后,我们使用 exceptionally() 方法来处理异常,并提供一个默认的返回值。在异常发生时,异常处理函数会被调用,打印异常信息,并返回 0。最后,我们使用 join() 方法等待异步任务完成,并获取最终结果。

需要注意的是,exceptionally() 方法返回的是一个新的 CompletableFuture 对象,它表示一个新的异步任务。这个新的任务在原始任务抛出异常时会被触发,并执行异常处理函数。

使用 exceptionally() 方法可以方便地处理异步任务的异常情况,提供默认的返回值或进行异常处理,从而保证程序的可靠性和稳定性。

2. handle()方法的使用

六、 CompletableFuture的进阶功能

1. CompletableFuture的取消和超时处理

handle() 方法是 CompletableFuture 类提供的一个方法,它可以在异步任务完成后对结果进行处理,无论是否出现异常。相比于 exceptionally() 方法,handle() 方法可以处理正常结果和异常情况。

handle() 方法接受一个函数作为参数,这个函数会在异步任务完成后被调用,并接收任务的结果作为输入参数。这个函数可以返回一个结果,作为最终的处理结果。

下面是 handle() 方法的使用示例:

import java.util.concurrent.CompletableFuture;public class HandleExample {public static void main(String[] args) {// 定义一个异步任务CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {// 任务逻辑,这里可能会抛出异常return 10;});// 使用 handle() 方法处理异步任务的结果和异常CompletableFuture<String> result = future.handle((value, ex) -> {if (ex != null) {// 异常处理System.out.println("Exception occurred: " + ex.getMessage());return "Default Value";} else {// 正常结果处理return "Result: " + value;}});// 等待异步任务完成并获取最终结果String finalResult = result.join();System.out.println(finalResult);}
}

在上面的示例中,我们定义了一个异步任务 future,它会返回一个整数。然后,我们使用 handle() 方法来处理异步任务的结果和异常。在处理函数中,首先判断异常是否为 null,如果不为 null,则表示任务发生了异常,我们可以在这里进行异常处理,并返回一个默认值。如果异常为 null,则表示任务执行正常,我们可以在这里对正常结果进行处理,并返回相应的字符串。

最后,使用 join() 方法等待异步任务完成,并获取最终的处理结果。

需要注意的是,handle() 方法返回的是一个新的 CompletableFuture 对象,它表示一个新的异步任务。这个新的任务会在原始任务完成后被触发,并执行处理函数。

通过使用 handle() 方法,我们可以灵活地处理异步任务的结果和异常,提供自定义的处理逻辑,从而实现更加复杂的业务需求。

2. CompletableFuture的并发限制

CompletableFuture 类本身并没有提供直接的并发限制功能。它是 Java 中用于处理异步编程的工具类,通过 CompletableFuture 可以方便地进行异步任务的组合、串行化、并行化等操作。

如果你需要对异步任务进行并发限制,可以借助 Executor 框架提供的线程池来实现。Executors 类提供了一些静态方法来创建不同类型的线程池,其中的线程池可以控制并发执行的任务数量。

下面是一个使用 Executors 创建固定大小线程池来限制 CompletableFuture 并发的示例:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ConcurrentLimitExample {public static void main(String[] args) {// 创建一个固定大小的线程池ExecutorService executor = Executors.newFixedThreadPool(5);// 创建多个 CompletableFuture,并指定线程池CompletableFuture<Void> task1 = CompletableFuture.runAsync(() -> {// 异步任务逻辑System.out.println("Task 1");}, executor);CompletableFuture<Void> task2 = CompletableFuture.runAsync(() -> {// 异步任务逻辑System.out.println("Task 2");}, executor);CompletableFuture<Void> task3 = CompletableFuture.runAsync(() -> {// 异步任务逻辑System.out.println("Task 3");}, executor);// 等待所有 CompletableFuture 完成CompletableFuture.allOf(task1, task2, task3).join();// 关闭线程池executor.shutdown();}
}

在上面的示例中,我们使用 Executors.newFixedThreadPool(5) 创建一个固定大小为 5 的线程池。然后,我们创建了多个 CompletableFuture 对象,并通过指定线程池来执行异步任务。通过这种方式,我们可以控制并发执行的任务数量,限制在线程池提供的线程数范围内。

需要注意的是,通过线程池控制并发执行的任务数量是有限度的,取决于线程池的配置和硬件资源。如果任务数超过了线程池的容量,超出部分的任务会进入等待队列,直到有空闲线程可用。

使用线程池来限制 CompletableFuture 的并发操作可以帮助控制资源的使用,防止资源过度消耗和线程过多导致的性能问题。

3. CompletableFuture与Stream的结合使用

CompletableFuture 和 Stream 是 Java 中两个强大且灵活的工具,它们可以很好地结合使用,以实现异步处理和流式操作的组合。下面是一些使用 CompletableFuture 和 Stream 结合的示例:

  1. 异步任务的并行处理:
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;public class CompletableFutureWithStream {public static void main(String[] args) {List<Integer> numbers = List.of(1, 2, 3, 4, 5);// 使用 CompletableFuture 来异步处理每个元素List<CompletableFuture<String>> futures = numbers.stream().map(number -> CompletableFuture.supplyAsync(() -> process(number))).collect(Collectors.toList());// 等待所有 CompletableFuture 完成,并获取结果列表List<String> results = futures.stream().map(CompletableFuture::join).collect(Collectors.toList());// 打印结果results.forEach(System.out::println);}private static String process(Integer number) {// 模拟一个耗时操作try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return "Processed: " + number;}
}

在上述示例中,我们使用 CompletableFuture 的 supplyAsync() 方法来创建异步任务,并通过 Stream 的 map() 方法将每个元素映射成对应的 CompletableFuture。然后,我们将这些 CompletableFuture 收集到一个列表中。

接着,我们通过 Stream 的 map() 方法将列表中的 CompletableFuture 转换为实际的结果,并将结果收集到另一个列表中。最后,我们打印出每个结果。

这样的方式可以实现异步任务的并行处理,提高处理效率。

  1. 异步任务的顺序处理:
import java.util.List;
import java.util.concurrent.CompletableFuture;public class CompletableFutureWithStream {public static void main(String[] args) {List<Integer> numbers = List.of(1, 2, 3, 4, 5);CompletableFuture<Void> future = CompletableFuture.completedFuture(null); // 创建一个已完成的 CompletableFuture// 顺序处理每个元素的异步任务for (Integer number : numbers) {future = future.thenComposeAsync(result -> CompletableFuture.supplyAsync(() -> process(number)));}// 等待最后一个 CompletableFuture 完成future.join();}private static String process(Integer number) {// 模拟一个耗时操作try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Processed: " + number);return null;}
}

在上述示例中,我们使用一个已完成的 CompletableFuture 作为起点。然后,我们在循环中以顺序的方式将每个元素的异步任务连接起来,通过 thenComposeAsync() 方法将每个异步任务串联起来。

通过这样的方式,每个异步任务都会等待前一个任务完成后才会触发执行,从而实现了顺序处理的效果。

需要注意的是,在顺序处理的情况下,后续的异步任务会等待前一个任务完成后才会被触发,所以整体的执行时间会比并行处理长。这取决于异步任务的耗时和处理逻辑。

通过 CompletableFuture 和 Stream 的结合使用,可以快速实现复杂的异步处理和流式操作。你可以根据具体的需求和业务场景选择合适的方式来组合它们。

七、 示例和案例分析

1. 使用CompletableFuture实现并发下载

使用 CompletableFuture 来实现并发下载是一个很常见的场景,下面是一个使用 CompletableFuture 实现并发下载的示例:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ConcurrentDownloader {public static void main(String[] args) {List<String> urls = Arrays.asList("https://example.com/image1.jpg","https://example.com/image2.jpg","https://example.com/image3.jpg");// 创建固定大小的线程池ExecutorService executor = Executors.newFixedThreadPool(3);// 使用 CompletableFuture 并发下载图片List<CompletableFuture<Void>> downloadFutures = urls.stream().map(url -> CompletableFuture.runAsync(() -> downloadImage(url), executor)).toList();// 等待所有 CompletableFuture 完成CompletableFuture.allOf(downloadFutures.toArray(new CompletableFuture[0])).join();// 关闭线程池executor.shutdown();}private static void downloadImage(String url) {try (InputStream in = new URL(url).openStream();FileOutputStream out = new FileOutputStream(getFileName(url))) {byte[] buffer = new byte[4096];int bytesRead;while ((bytesRead = in.read(buffer)) != -1) {out.write(buffer, 0, bytesRead);}System.out.println("Downloaded: " + url);} catch (IOException e) {System.err.println("Failed to download image: " + url);}}private static String getFileName(String url) {String[] segments = url.split("/");return segments[segments.length - 1];}
}

在上述示例中,我们首先创建了一个包含要下载图片的 URL 列表。然后,我们创建了一个固定大小的线程池,通过 Executors.newFixedThreadPool(3) 创建了一个大小为 3 的线程池。

接下来,我们使用 CompletableFuture 和 Stream 的结合来并发下载图片。通过 CompletableFuture.runAsync() 方法将下载图片的逻辑包装成一个异步任务,并指定线程池执行该任务。然后,将所有的 CompletableFuture 收集到一个列表中。

最后,我们使用 CompletableFuture.allOf() 方法来等待所有的 CompletableFuture 完成,并通过 join() 方法阻塞当前线程,直到所有任务完成。

需要注意的是,并发下载图片涉及到网络 IO 操作,可能会耗费较长的时间。为了避免阻塞主线程,我们采用了异步的方式进行下载,并且使用了线程池来控制并发执行的任务数量。

通过 CompletableFuture 的使用,我们可以简洁地实现并发下载的功能,并可以灵活地控制并发度和线程池的大小。这样可以提高下载效率,并充分利用可用的资源。

2. 使用CompletableFuture优化订单处理流程

使用 CompletableFuture 可以优化订单处理流程,提高效率和并发性。下面是一个使用 CompletableFuture 优化订单处理流程的示例:

假设有一个订单处理系统,包含以下几个步骤:验证订单、扣除库存、生成发货单、发送通知。

import java.util.concurrent.CompletableFuture;public class OrderProcessing {public static void main(String[] args) {CompletableFuture<Void> orderProcessingFuture = CompletableFuture.completedFuture(null);// 验证订单orderProcessingFuture = orderProcessingFuture.thenComposeAsync(result -> CompletableFuture.supplyAsync(() -> validateOrder())).thenApplyAsync(result -> {if (result) {System.out.println("订单验证通过");} else {System.out.println("订单验证失败");}return result;});// 扣除库存orderProcessingFuture = orderProcessingFuture.thenComposeAsync(result -> CompletableFuture.supplyAsync(() -> deductInventory())).thenAcceptAsync(result -> {if (result) {System.out.println("库存扣除成功");} else {System.out.println("库存扣除失败");}});// 生成发货单orderProcessingFuture = orderProcessingFuture.thenComposeAsync(result -> CompletableFuture.supplyAsync(() -> generateInvoice())).thenAcceptAsync(invoice -> {System.out.println("发货单生成成功:" + invoice);});// 发送通知orderProcessingFuture = orderProcessingFuture.thenRunAsync(() -> sendNotification());// 等待订单处理完成orderProcessingFuture.join();}private static boolean validateOrder() {// 模拟订单验证操作try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return true;}private static boolean deductInventory() {// 模拟扣除库存操作try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return true;}private static String generateInvoice() {// 模拟生成发货单操作try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return "Invoice-123456";}private static void sendNotification() {// 模拟发送通知操作try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("通知已发送");}
}

在上述示例中,我们通过 CompletableFuture 来优化订单处理流程。每个步骤都被封装为一个异步任务,并使用 thenComposeAsync() 方法将前一个任务的结果传递给下一个任务。同时,通过 thenApplyAsync()thenAcceptAsync()thenRunAsync() 方法可以在任务完成后执行相应的操作。

在验证订单、扣除库存和生成发货单这些关键步骤中,我们使用 CompletableFuture.supplyAsync() 方法来创建异步任务。这些任务会异步地执行相关操作,并返回结果或者不返回。

最后,在订单处理完成后,我们使用 join() 方法阻塞主线程,等待所有任务完成。

通过使用 CompletableFuture,我们可以以一种非常直观和简洁的方式组织和优化订单处理流程。异步任务的执行不会阻塞主线程,可以提高并发性和系统的响应能力。

八、总结

1. 重点总结CompletableFuture的核心概念和用法

CompletableFuture 是 Java 8 引入的一个用于处理异步编程的工具类,它提供了丰富的方法来处理异步任务和操作结果。下面是 CompletableFuture 的核心概念和用法的总结:

  1. 异步任务的创建:使用 CompletableFuture.supplyAsync()CompletableFuture.runAsync()
    CompletableFuture.completedFuture() 方法来创建异步任务。supplyAsync()
    runAsync() 分别用于有返回值和无返回值的异步任务的创建。

  2. 异步任务的串行关系:通过 thenApply()thenAccept()thenRun() 方法将一个任务与另一个任务进行串联。thenApply() 用于对上一个任务的结果进行转换,thenAccept()
    用于消费上一个任务的结果,thenRun() 用于在上一个任务完成后执行一段代码。

  3. 异步任务的并行关系:通过 thenCombine()thenAcceptBoth()runAfterBoth() 等方法将多个任务进行组合。这些方法用于在多个任务之间建立依赖关系,并在它们都完成后进行相应的操作。

  4. 异步任务的异常处理:使用 exceptionally() 方法或 handle() 方法来处理异步任务中的异常。exceptionally() 方法用于处理异常,并返回一个默认值,handle()
    方法可以处理异常,并提供一个替代的计算结果。

  5. 异步任务的等待和合并:使用 join() 方法等待一个任务的完成,并获取其结果。使用 allOf() 方法等待多个任务的完成,或者使用 anyOf() 方法等待任意一个任务的完成。

  6. 异步任务的组合和并发控制:使用 thenCompose()thenCombine()allOf() 等方法对多个任务进行组合和并发控制。thenCompose()
    用于将前一个任务的结果作为下一个任务的输入,thenCombine() 用于将两个任务的结果进行合并,allOf()
    用于等待多个任务的完成。

  7. 线程池的使用:可以通过 CompletableFuture.runAsync()CompletableFuture.supplyAsync()
    CompletableFuture.thenRunAsync() 等方法指定自定义的线程池来执行异步任务。

CompletableFuture 提供了一种方便而强大的方式来处理异步编程,可以避免显式地使用线程或回调函数来处理异步操作。它具有丰富的方法和组合功能,可以实现复杂的异步流程控制和并发控制。通过合理地应用 CompletableFuture,我们可以提高程序的性能和可读性。

2. 强调CompletableFuture在多线程编程中的价值和应用场景

CompletableFuture 在多线程编程中具有重要的价值和广泛的应用场景。下面是强调 CompletableFuture 在多线程编程中的价值和常见的应用场景:

  1. 并行任务执行:CompletableFuture 可以方便地启动多个异步任务,并发地执行它们,从而提高系统的并发性和吞吐量。通过将任务串联或组合起来,可以构建复杂的任务流水线和并发控制逻辑。

  2. 异步操作与非阻塞调用:CompletableFuture 支持异步任务的创建和执行,可以在异步任务执行过程中继续执行其他操作,而不需要显式地创建和管理线程。这样可以避免阻塞主线程,提高系统的响应能力和资源利用率。

  3. 响应式编程:CompletableFuture 的链式操作和回调函数机制使其非常适合用于实现响应式编程模型。我们可以通过 thenApply、thenAccept、thenRun 等方法定义异步任务的处理逻辑,并在任务完成后自动触发回调函数进行后续的操作。

  4. 异常处理和容错机制:CompletableFuture 提供了丰富的异常处理方法,例如 exceptionally、handle 等,可以方便地处理异步任务中出现的异常,并提供默认值或备用计算结果。这样可以增强程序的健壮性和容错性。

  5. 并发控制和任务合并:CompletableFuture 提供了多种方法来控制异步任务的并发度,例如 thenCompose、thenCombine、allOf 等。通过合理地组合和并发控制,可以实现更高效的任务调度和资源管理。

  6. 自定义线程池:CompletableFuture 允许我们通过指定自定义的 Executor 来执行异步任务,从而可以灵活地控制线程池的大小、线程池的属性等,以满足应用程序的需求。

  7. 异步 I/O 操作:CompletableFuture 还可以与异步 I/O 操作结合使用,例如与 NIO 的 AsynchronousFileChannel、AsynchronousSocketChannel 等配合,实现高效的异步文件读写和网络通信。

CompletableFuture 在多线程编程中具有强大的功能和灵活的应用场景。它简化了异步编程的复杂性,提高了代码的可读性和可维护性,同时也提升了系统的性能和并发性。无论是对于高并发的服务器端应用,还是对于异步处理的客户端应用,CompletableFuture 都是一个强大的工具。

相关文章:

「Java」《深入解析Java多线程编程利器:CompletableFuture》

《深入解析Java多线程编程利器&#xff1a;CompletableFuture》 一、 引言1. 对多线程编程的需求和挑战的介绍2. 介绍CompletableFuture的作用和优势 二. CompletableFuture简介1. CompletableFuture是Java中提供的一个强大的多线程编程工具2. 与传统的Thread和Runnable相比的优…...

Docker容器与虚拟化技术:容器运行时说明与比较

目录 一、理论 1.容器运行时 2.容器运行时接口 3.容器运行时层级 4.容器运行时比较 5.强隔离容器 二、问题 1.K8S为何难以实现真正的多租户 三、总结 一、理论 1.容器运行时 &#xff08;1&#xff09;概念 Container Runtime 是运行于 k8s 集群每个节点中&#xff…...

vue导出文件流获取附件名称并下载(在response.headers里解析filename导出)

导出文件流下载&#xff0c;拦截器统一处理配置 需求以往实现的方法&#xff08;各自的业务层写方法&#xff09;现在实现的方法&#xff08;axios里拦截器统一配置处理&#xff09;把文章链接复制粘贴给后端&#xff0c;让大佬自己赏阅。 需求 之前实现的导出都是各自的业务层…...

​山东省图书馆典藏《乡村振兴战略下传统村落文化旅游设计》鲁图中大许少辉博士八一新书

​山东省图书馆《乡村振兴战略下传统村落文化旅游设计》鲁图中大许少辉博士八一新书...

2023-08-19力扣每日一题-水题/位运算解法

链接&#xff1a; 2235. 两整数相加 题意&#xff1a; ab 解&#xff1a; ab 补一个位运算写法&#xff0c;进位是(a&b)<<1&#xff0c;不进位的计算结果为a^b 实际代码&#xff1a; #include<iostream> using namespace std; int sum(int num1, int n…...

Hadoop学习:深入解析MapReduce的大数据魔力之数据压缩(四)

Hadoop学习&#xff1a;深入解析MapReduce的大数据魔力之数据压缩&#xff08;四&#xff09; 4.1 概述1&#xff09;压缩的好处和坏处2&#xff09;压缩原则 4.2 MR 支持的压缩编码4.3 压缩方式选择4.3.1 Gzip 压缩4.3.2 Bzip2 压缩4.3.3 Lzo 压缩4.3.4 Snappy 压缩4.3.5 压缩…...

LRU淘汰策略执行过程

1 介绍 Redis无论是惰性删除还是定期删除&#xff0c;都可能存在删除不尽的情况&#xff0c;无法删除完全&#xff0c;比如每次删除完过期的 key 还是超过 25%&#xff0c;且这些 key 再也不会被客户端访问。 这样的话&#xff0c;定期删除和堕性删除可能都彻底的清理掉。如果…...

Kotlin 高阶函数详解

高阶函数 在 Kotlin 中&#xff0c;函数是一等公民&#xff0c;高阶函数是 Kotlin 的一大难点&#xff0c;如果高阶函数不懂的话&#xff0c;那么要学习 Kotlin 中的协程、阅读 Kotlin 的源码是非常难的&#xff0c;因为源码中有太多高阶函数了。 高阶函数的定义 高阶函数的…...

DL——week2

要学明白的知识点&#xff1a; np.dot()的作用 两个数组的点积&#xff0c;即对应元素相乘 numpy.dot(a,b,outNone) a: ndarray 数组 b: ndarray 数组 out: ndarray, 可选&#xff0c;用来保存dot&#xff08;&#xff09;的计算结果 numpy Ndarray对象 N维数组对象ndarray&am…...

如何撰写骨灰级博士论文?这是史上最全博士论文指导!

博士论文的写作是博士研究生主要要完成的工作。由于存在着较高的难度&#xff0c;较长的写作周期&#xff0c;以及在创新&#xff0c;写作规范&#xff0c;实际及理论意义等方面有着比较高的要求&#xff0c;博士论文的完成一般说来是有相当难度的。一篇好的博士论文不仅是一本…...

08.SpringBoot请求相应

文章目录 1 请求1.1 Postman1.2 简单参数1.2.1 原始方式1.2.2 SpringBoot方式1.2.3 参数名不一致 1.3 实体参数1.3.1 简单实体对象1.3.2 复杂实体对象 1.4 数组集合参数1.4.1 数组1.4.2 集合 1.5 日期参数1.6 JSON参数1.7 路径参数 2 响应2.1 ResponseBody注解2.2 统一响应结果…...

C#详解-Contains、StartsWith、EndsWith、Indexof、lastdexof

目录 简介: 过程: 举例1.1 举例1.2 ​ 总结: 简介: 在C#中Contains、StarsWith和EndWith、IndexOf都是字符串函数。 1.Contains函数用于判断一个字符串是否包含指定的子字符串&#xff0c;返回一个布尔值&#xff08;True或False&#xff09;。 2.StartsWith函数用于判断一…...

FATE框架中pipline基础教程

目录 1. 用pipline上传数据2. 用 Pipeline 进行 Hetero SecureBoost 的训练和预测3. 用 Pipeline 构建神经网络模型3.1 Homo-NN Quick Start: A Binary Classification Task3.2 Hetero-NN Quick Start: A Binary Classification Task 4. 自定义数据集示例&#xff1a;实现一个简…...

Atlas 元数据管理

Atlas 元数据管理 1.Atlas入门 1.1概述 元数据原理和治理功能&#xff0c;用以构建数据资产的目录。对这个资产进行分类和管理&#xff0c;形成数据字典。 提供围绕数据资产的协作功能。 表和表之间的血缘依赖 字段和字段之间的血缘依赖 1.2架构图 导入和导出&#xff1…...

编程题练习@8-23

分享8月23日两道编程题&#xff1a; 1 开幕式排列 题目描述 导演在组织进行大运会开幕式的排练&#xff0c;其中一个环节是需要参演人员围成一个环形。 演出人员站成了一圈&#xff0c;出于美观度的考虑&#xff0c;导演不希望某一个演员身边的其他人比他低太多或者高太多。 现…...

static相关知识点详解

文章目录 一. 修饰成员变量二. 修饰成员方法三. 修饰代码块四. 修饰类 一. 修饰成员变量 static 修饰的成员变量&#xff0c;称为静态成员变量&#xff0c;该变量不属于某个具体的对象&#xff0c;是所有对象所共享的。 public class Student {private String name;private sta…...

Redisson 分布式锁

Redis是基础客户端库&#xff0c;可用于执行基本操作。 Redisson是基于Redis的Java客户端&#xff0c;提供高级功能如分布式锁、分布式集合和分布式对象。 Redisson提供更友好的API&#xff0c;支持异步和响应式编程&#xff0c;提供内置线程安全和失败重试机制。 实现步骤…...

继承(C++)

继承 一、初识继承概念“登场”语法格式 继承方式九种继承方式组合小结&#xff08;对九种组合解释&#xff09; 二、继承的特性赋值转换 一一 切片 / 切割作用域 一一 隐藏 / 重定义 三、派生类的默认成员函数派生类的默认成员函数1. 构造函数2. 拷贝构造3. 赋值运算符重载4. …...

文心一言 VS 讯飞星火 VS chatgpt (80)-- 算法导论7.4 5题

五、如果用go语言&#xff0c;当输入数据已经“几乎有序”时&#xff0c;插入排序速度很快。在实际应用中&#xff0c;我们可以利用这一特点来提高快速排序的速度。当对一个长度小于 k 的子数组调用快速排序时&#xff0c;让它不做任何排序就返回。当上层的快速排序调用返回后&…...

SpringCloud 概述

文章目录 SpringCloud 概述一、微服务中的相关概念1、服务注册与发现2、负载均衡3、熔断4、链路追踪5、API网关 二、SpringCloud的介绍三、SpringCloud的架构1、SpringCloud中的核心组件&#xff08;1&#xff09;Spring Cloud Netflix组件&#xff08;2&#xff09;Spring Clo…...

Apache ShenYu 学习笔记一

1、简介 这是一个异步的&#xff0c;高性能的&#xff0c;跨语言的&#xff0c;响应式的 API 网关。 官网文档&#xff1a;Apache ShenYu 介绍 | Apache ShenYu仓库地址&#xff1a;GitHub - apache/shenyu: Apache ShenYu is a Java native API Gateway for service proxy, pr…...

uniapp 禁止遮罩层下的页面滚动

使用 touchmove.stop.prevent"toMoveHandle" 事件修饰符 若需要禁止蒙版下的页面滚动&#xff0c;可使用 touchmove.stop.prevent"moveHandle"&#xff0c;moveHandle 可以用来处理 touchmove 的事件&#xff0c;也可以是一个空函数。将这个方法直接丢到弹…...

postgresql 分组

postgresql 数据汇总 分组汇总聚合函数注意 总结 分组统计总结 高级分组总结 分组汇总 聚合函数 聚合函数&#xff08;aggregate function&#xff09;针对一组数据行进行运算&#xff0c;并且返回单个结果。PostgreSQL 支持以下常见的聚合函数&#xff1a; • AVG - 计算一…...

RT1052的EPWM

文章目录 1 EPWM介绍1.1 引脚1.2 时钟1.3 比较寄存器 2 函数 1 EPWM介绍 RT1052 具有 4 个 eFlexPWM(eFlexWM1~eFlex_PWM4)。 每个 eFlexPWM 可以产生四路互补 PWM即产生 8 个 PWM&#xff0c;也可以产生相互独立的 PWM 波。四路分别是模块0-3每个 eFlexPWM 具有各自的故障检…...

k8s 安装istio (一)

前置条件 已经完成 K8S安装过程十&#xff1a;Kubernetes CNI插件与CoreDNS服务部署 部署 istio 服务网格与 Ingress 服务用到了 helm 与 kubectl 这两个命令行工具&#xff0c;这个命令行工具依赖 ~/.kube/config 这个配置文件&#xff0c;目前只在 kubernetes master 节点中…...

vue 项目在编译时,总是出现系统崩的状态,报错信息中有v7 或者 v8 的样式-项目太大内存溢出

vue 项目在编译时&#xff0c;总是出现系统崩的状态&#xff0c;node 命令框也会报错&#xff0c;如下图&#xff1a;有v7 或者 v8 的样式。 原因分析&#xff1a; 分析&#xff1a;遇到与上面图片相似的问题&#xff0c;我们要首先要想到是否是 有关内存的问题&#xff0c;当然…...

低功耗蓝牙射频指纹识别

射频指纹 射频指纹是什么 射频指纹是一种利用无线电信号的特征来识别设备或用户的技术。射频指纹可以用来做设备身份认证、位置跟踪、安全防护等应用。射频指纹的优点是难以伪造、不依赖于额外的硬件或软件、适用于多种无线通信协议。 射频指纹识别流程 射频指纹识别的一般…...

怎么检测UI卡顿?(线上及线下)

什么是UI卡顿&#xff1f; 在Android系统中&#xff0c;我们知道UI线程负责我们所有视图的布局&#xff0c;渲染工作&#xff0c;UI在更新期间&#xff0c;如果UI线程的执行时间超过16ms&#xff0c;则会产生丢帧的现象&#xff0c;而大量的丢帧就会造成卡顿&#xff0c;影响用…...

Git 常用操作

一、Git 常用操作 1、切换分支 git checkout命令可以用于三种不同的实体&#xff1a;文件&#xff0c;commit&#xff0c;以及分支。checkout的意思就是对于一种实体的不同版本之间进行切换的操作。checkout一个分支&#xff0c;会更新当前的工作空间中的文件&#xff0c;使其…...

前端修改新增操作导致数据删除——js精度丢失

问题描述 笔者在写前端渲染表格的时候&#xff0c;发现无论是修改还是新增&#xff0c;数据都会被删除。检查了前端逻辑并与后端联调均无问题。 然后就开始和后端一起对数据库&#xff0c;结果发现&#xff0c;十几位的id&#xff0c;接收过来的时候&#xff0c;尾数均变为了…...

wordpress 毛玻璃/性价比高的seo网站优化

linux 编写计划任务 (crontab任务)转载凯里欧文 最后发布于2018-07-06 13:42:40 阅读数 2481 收藏crontab 一些常用的命令service crond start //启动服务service crond stop //关闭服务service crond restart //重启服务service crond reload //重新载入配置chmod x dbackup.s…...

鹤壁网站制作/百度客服人工电话24

【老杨注&#xff1a;本文是51CTO.com编辑李棉原创&#xff0c;老杨未加改动。】微软持之以恒欲将OOXML文档标准升级为国际标准上周总算有了定论&#xff0c;微软OOXML申请国际文档标准已获通过&#xff0c;但是中国投反对票。全球***大赛的 第二天&#xff0c;一组参赛***在不…...

青岛知名网站建设公司/百度推广登录平台网址

导读&#xff1a;一直以来&#xff0c;众多学校教学以及公司开发环境所使用Visual Studio .NET Framework版本多不相同&#xff0c;本文作者比较了.NET Framework多个版本之间的区别&#xff0c;方便各位选择和切换.NET Framework。 版本号发布日期Visual Studio的版本Windows上…...

自己做卖东西网站/免费大数据查询

问题描述在操作系统中&#xff0c;数据通常以文件的形式存储在文件系统中。文件系统一般采用层次化的组织形式&#xff0c;由目录&#xff08;或者文件夹&#xff09;和文件构成&#xff0c;形成一棵树的形状。文件有内容&#xff0c;用于存储数据。目录是容器&#xff0c;可包…...

做网站实例/百度指数数据分析平台

一、什么是Nginx? Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;其特点是占有内存少&#xff0c;并发能力强&#xff0c;中国大陆使用nginx网站用户有&#xff1a;百度、京东、新浪、网易、腾讯、淘宝等。…...

品质培训网站建设/百度网址大全 旧版本

复习详尽攻略&#xff1a;梦圆华工中探花自助者天助之&#xff0c;考研也是如此。你必须十分努力&#xff0c;才能看起来毫不费力。下面分享一位前辈的考研经验。作者91淘气小卒次阅读2017-01-16【摘要】自助者天助之&#xff0c;考研也是如此。你必须十分努力&#xff0c;才能…...