Java线程池
几种线程池简介
Executors.
newFixedThreadPool
创建⼀个固定⼤⼩的线程池,可控制并发的线程数,超出的线程会在队列中等待;
Executors.
newCachedThreadPool
创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数不够,则新建线程;
Executors.
newSingleThreadExecutor
创建单个线程数的线程池,它可以保证先进先出的执⾏顺序;
Executors.
newScheduledThreadPool
创建⼀个可以执⾏延迟任务的线程池;
scheduleAtFixedRate
是以period为间隔来执行任务的,如果任务执行时间小于period,则上次任务执行完成后会间隔period后再去执行下一次任务;但如果任务执行时间大于period,则上次任务执行完毕后会不间隔的立即开始下次任务
scheduleWithFixedDelay 是不管任务执行多久,都会等上一次任务执行完毕后再延迟delay后去执行下次任务
Executors.
newSingleThreadScheduledExecutor
创建⼀个单线程的可以执⾏延迟任务的线程池
Executors.
newWorkStealingPool
创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确定)【JDK1.8 添加】。
ThreadPoolExecutor
最原始的创建线程池的⽅式,它包含了 7 个参数可供设置。
ThreadPoolExecutor线程池
ThreadPoolExecutor
是Java中最灵活、最常用的线程池。
ThreadPoolExecutor
是一个灵活的线程池实现,可以通过调整参数来满足不同的需求,例如设置核心线程数、最大线程数、等待队列、拒绝策略等。
ThreadPoolExecutor
还提供了预定义的线程池,例如Executors.newFixedThreadPool
、Executors.newCachedThreadPool
等,这些预定义线程池都是基于ThreadPoolExecutor
实现的,但是它们的参数是固定的,比较适合一些特定的场景。因此,ThreadPoolExecutor
是Java中最灵活、最常用的线程池实现。
ThreadPoolExecutor
是Java中线程池的实现类,其构造方法有7个参数,分别为:
-
corePoolSize
:线程池中的核心线程数,即线程池中始终保持的线程数,即使它们处于空闲状态也不会被销毁。如果提交的任务数小于corePoolSize,则线程池会创建新线程来处理任务,即使此时有空闲线程存在。 -
maximumPoolSize
:线程池中允许的最大线程数,包括核心线程和非核心线程。当提交的任务数超过corePoolSize时,线程池会尝试创建新的线程来处理任务,但创建的线程数不能超过maximumPoolSize。如果任务队列已满并且已经创建了maximumPoolSize个线程,则线程池会拒绝提交新任务。 -
keepAliveTime
:非核心线程空闲时间的超时时间,当非核心线程在空闲时间超过keepAliveTime时,它们将被终止并从线程池中删除,直到线程池中的线程数小于corePoolSize为止。如果keepAliveTime为0,则非核心线程将不会被终止。 -
unit
:keepAliveTime的时间单位,可以是秒、毫秒、微秒等。 -
workQueue
:任务队列,用于保存等待执行的任务。ThreadPoolExecutor提供了多种类型的队列,如SynchronousQueue、LinkedBlockingQueue、ArrayBlockingQueue等。 -
threadFactory
:线程工厂,用于创建新的线程来执行任务。可以自定义线程工厂来创建自己的线程,例如设置线程名、优先级等。在Java中,可以使用ThreadFactory接口来自定义线程工厂,该接口只有一个方法newThread(Runnable r),用于创建一个新的线程。常见的线程工厂实现如下: 1. DefaultThreadFactory:JDK提供的默认线程工厂,用于创建普通的线程。它会创建一个新的Thread对象,使用Runnable。并设置线程名、优先级、守护线程标志等属性。 2. NamedThreadFactory:自定义的线程工厂,用于创建有名字的线程。该工厂会为每个线程设置一个名字,格式为prefix-N-thread-M,其中prefix为前缀,N为线程池编号,thread-M为线程编号。 3. PriorityThreadFactory:自定义的线程工厂,用于创建具有优先级的线程。该工厂会为每个线程设置一个优先级,可以在创建线程时指定优先级。 4. CustomizableThreadFactory:自定义的线程工厂,用于创建自定义的线程。该工厂可以自定义线程名、优先级、守护线程标志、线程组等属性。 5. SpringThreadFactory:Spring框架提供的线程工厂,用于创建可管理的线程。该工厂会创建一个新的线程,并将其注册到Spring的线程管理器中,以便管理线程的状态和执行情况。 以上是常见的线程工厂实现,当然你也可以自定义实现ThreadFactory接口来创建自己的线程工厂。
-
handler
:拒绝策略,当线程池中的线程已经用完并且阻塞队列已满时,ThreadPoolExecutor将拒绝提交新任务。拒绝策略提供了4种处理方式:1. CallerRunsPolicy:调用者运行策略,当线程池无法处理新任务时,将任务返回给提交任务的线程来执行(即在提交任务的线程中直接执行任务)。 2. AbortPolicy:线程池默认的拒绝策略。抛弃策略,当线程池无法处理新任务时,直接抛弃该任务并抛出RejectedExecutionException异常。 3. DiscardPolicy:忽视,什么都不会发生。当新任务被提交后直接被丢弃掉,也不会给你任何的通知,相对而言存在一定的风险 4. DiscardOldestPolicy:抛弃最旧的策略,当线程池无法处理新任务时,抛弃队列中最早提交的任务,并尝试重新提交新任务。即:从队列中踢出最先进入队列(最后一个执行)的任务 如果以上4种策略都无法满足需求,可以自定义拒绝策略,只需要实现RejectedExecutionHandler接口即可。
运行步骤
当有任务提交到线程池时,线程池会按照以下步骤处理任务:
- 如果
当前活动线程数
小于核心线程数
,则创建新的工作线程来处理任务,并将任务交给该线程执行,直到当前活动线程数
等于核心线程数
。 - 如果
当前活动线程数
等于核心线程数
,则将任务放入阻塞队列
中等待执行,直到阻塞队列
已满。 - 如果
阻塞队列
已满且当前线程数
小于最大线程数
,则创建新的工作线程来处理任务,并将任务交给该线程执行,直到达到最大线程数
- 如果
当前线程数
已经达到最大线程数
,则拒绝执行新的任务,根据设置的拒绝策略
进行处理。 - 当线程池中的
工作线程完成任务
后,它们会继续从阻塞队列
中取出任务执行,直到线程池关闭。
参数设置
orePoolSize
核心线程数,默认为1。
设置规则:
- CPU密集型(CPU密集型也叫计算密集型,指的是运算较多,cpu占用高,读/写I/O(硬盘/内存)较少):corePoolSize = CPU核数 + 1。
- IO密集型(与cpu密集型相反,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高。):corePoolSize = CPU核数 * 2
keepAliveTime
线程空闲时间,默认为60s,一般设置为默认60s
unit
时间单位,默认为秒
handler
拒绝策略,默认是AbortPolicy,会抛出异常
配置示例
具体使用代码配置参考
@Async
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class AsyncConfig {
@Bean(name = "asyncExecutor")
public ThreadPoolTaskExecutor asyncExecutor() {
//ThreadPoolTaskExecutor是Spring框架提供的一个线程池实现。
//ThreadPoolTaskExecutor内部维护了ThreadPoolExecutor,并通过各种方法设置其参数(核心线程、队列、最大线程数等)
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(10);
// 最大线程数
executor.setMaxPoolSize(100);
// 队列容量,如果此数字大于0,使用队列LinkedBlockingQueue
executor.setQueueCapacity(100);
// 线程名称前缀
executor.setThreadNamePrefix("AsyncThread-");
/**
* 使用自定义线程工厂
* 如果不设置则使用默认的DefaultThreadFactory,调用Runnable来执行任务
*/
executor.setThreadFactory(new TtlThreadFactory());
//初始化
executor.initialize();
return executor;
}
}
自定义TtlThreadFactory线程工厂,使用阿里的TtlRunnable执行任务。
import com.alibaba.ttl.TtlRunnable;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class TtlThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
TtlThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-ttlThread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, TtlRunnable.get(r),
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
线程池的任务队列
任务队列(BlockingQueue)指存放被提交但尚未被执行的任务
的队列。包括以下几种类型:直接提交的、有界的、无界的、优先任务队列。
直接提交的任务队列(SynchronousQueue)
-
没有容量限制
-
提交的任务不会被真实的保存在队列中,而总是将新任务提交给线程执行。如果没有空闲的线程,则尝试创建新的线程。如果线程数大于最大线程数,则执行拒绝策略
SynchronousQueue:
在Java线程池中,如果使用SynchronousQueue
作为任务队列,它实际上会将任务直接交给线程池中的工作线程进行处理,而不会将任务先存储在队列中。当一个任务提交给线程池后,如果有空闲的线程可用,则任务会立即交给可用的线程进行处理。如果没有可用的线程,新任务的提交将被阻塞,直到有线程可用。
因为SynchronousQueue
的容量为0,所以它不会存储任务,可以看作是一个零容量的队列。这也意味着,如果所有线程都在处理任务并且没有空闲的线程可用,新的任务提交将被阻塞,直到有线程空闲为止。
需要注意的是,使用SynchronousQueue
作为任务队列可能会导致线程池的负载非常高,因为每个任务都会直接交给工作线程处理。如果任务提交速度过快,而线程池的处理速度跟不上,可能会导致系统负载过高。因此,在使用SynchronousQueue
作为任务队列时,需要谨慎评估任务提交的速率和线程池的处理能力。
有界的任务队列(ArrayBlockingQueue、LinkedBlockingQueue)
- 创建队列时,指定队列的最大容量。
- 若有新的任务要执行,如果线程池中的线程数小于核心线程数,则会优先创建新的线程。若大于核心线程数,则会将新任务加入到队列中等待。
- 若队列已满,无法加入。如果总线程数不大于线程最大数,则创建新的线程执行任务。若大于线程最大数,则执行拒绝策略。
队列
ArrayBlockingQueue
:一个基于数组结构的有界阻塞队列,按FIFO(先进先出)原则对元素进行排序。LinkedBlockingQueue
:一个基于链表结构的有界阻塞队列,按FIFO原则对元素进行排序。可以指定容量,如果不指定则默认为Integer.MAX_VALUE
。
无界的任务队列(LinkedBlockingQueue)
-
与有界队列相比,除非系统资源耗尽,否则不存在任务入队失败的情况。也可以说没有容量限制
-
若有新的任务要执行,如果线程池中的线程数小于
核心线程数
,线程池会创建新的线程。若大于核心线程数
,此时又没有空闲的线程资源,则任务直接进入等待队列。 -
当线程池中的线程数达到核心线程数后,线程池不会创建新的线程。
若任务创建和处理的速度差异很大,无界队列将保持快速增长,直到耗尽系统内存。
使用无界队列将会导致核心线程数所有线程都在忙时,新任务全都在队列中等待。这样,创建的线程就不会超过 核心线程数(因此,最大线程数 的值也就无效了
)。
适用场景:
当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;或当任务量非常大时,无界任务队列可以避免任务被拒绝的情况
例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
队列
LinkedBlockingQueue
:除了作为有界队列的选项外,它还可以作为无界队列。如果不指定容量,则默认为Integer.MAX_VALUE
。
在ThreadPoolTaskExecutor
的源码中,创建队列时,如果指定容量大于0,使用LinkedBlockingQueue
,小于0使用SynchronousQueue
:
优先任务队列(PriorityBlockingQueue)
- 带有执行优先级的队列。是一个特殊的无界队列。
ArrayBlockingQueue
和LinkedBlockingQueue
都是按照先进先出算法来处理任务。而PriorityBlockingQueue
可根据任务自身的优先级顺序先后执行(总是确保高优先级的任务先执行)
优先任务队列是一种根据任务的优先级进行排序的队列,当任务到达线程池时,线程池会根据任务的优先级将任务插入到合适的位置,优先级高的任务会被优先执行。
PriorityBlockingQueue
:一个支持优先级排序的无界阻塞队列,元素按照它们的自然顺序或者通过构造函数提供的Comparator进行排序。
java异步使用
Java 实现异步有以下几种方法:
- 回调函数(Callback):将异步操作完成后执行的代码封装成回调函数,传递给异步操作,等异步操作完成后调用回调函数进行处理。
- Future 和 Promise:通过 Future 和 Promise 来管理异步操作的结果,Future 表示一个异步操作的结果,Promise 用于设置异步操作的结果。
- CompletableFuture:Java 8 引入的 CompletableFuture 类,提供了一种更为便捷的异步编程方式,可以轻松地进行异步操作的组合和串联。
- Reactive 编程:使用类似 RxJava、Reactor、Akka 等框架,采用响应式编程的方式实现异步操作。
总之,Java 实现异步的方法有很多,选择适合自己项目的方式即可。
回调函数
以下是使用回调函数实现异步的代码示例:
public interface Callback {
void onSuccess(String result);
void onFailure(Exception exception);
}
public class AsyncTask {
public static void doSomethingAsync(Callback callback) {
new Thread(() -> {
try {
// 模拟异步操作
Thread.sleep(1000);
String result = "异步操作的结果";
callback.onSuccess(result);
} catch (Exception e) {
callback.onFailure(e);
}
}).start();
}
}
public class Main {
public static void main(String[] args) {
System.out.println("开始执行异步操作");
AsyncTask.doSomethingAsync(new Callback() {
@Override
public void onSuccess(String result) {
System.out.println("异步操作成功,结果为:" + result);
}
@Override
public void onFailure(Exception exception) {
System.out.println("异步操作失败,异常为:" + exception.getMessage());
}
});
System.out.println("异步操作执行中,请稍等...");
}
}
以上代码中,定义了一个 Callback
接口,包含 onSuccess
和 onFailure
两个方法。
AsyncTask
类中的 doSomethingAsync
方法模拟了一个异步操作,该方法接收一个 Callback
对象作为参数,异步操作完成后调用 Callback
对象的 onSuccess
或 onFailure
方法进行处理。
在 Main
类中,调用 AsyncTask.doSomethingAsync
方法,传入一个 Callback
对象,然后输出异步操作执行中的提示信息。当异步操作完成后,根据操作结果调用相应的方法进行处理。
Future和Promise
Future
Future是一个表示异步计算结果的接口。当我们发起一个异步任务时,可以通过Future来获取任务的结果。
Future接口提供了一些方法来检查任务是否已完成、等待任务完成以及获取任务的结果。
例如,可以使用isDone()
方法来检查任务是否已完成,使用get()
方法来获取任务的结果(如果任务已完成,没有完成的话,调用get方法可能会导致调用线程阻塞
)。
Promise
Promise是Future的一个扩展接口,它提供了一些额外的方法来操作Future的结果。
Promise比Future多了以下方法:
- 通过调用
set()
方法或setException()
方法来设置任务的结果或异常 - 提供了
isCompleted()
方法来检查任务是否已完成 - 调用
cancel()
方法来取消任务的执行
代码示例
下面是使用Java中的Future和Promise的一个简单示例:
import java.util.concurrent.*;
public class FuturePromiseExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//定长线程池,2个
ExecutorService executor = Executors.newFixedThreadPool(2);
// 使用Future获取异步任务的结果:从线程池拿出一个线程并执行其run方法,返回一个42
Future<Integer> future = executor.submit(() -> {
Thread.sleep(1000);
return 42;
});
System.out.println("Waiting for the future...");
//如果任务未完成,等1秒
while (!future.isDone()) {
Thread.sleep(100);
}
System.out.println("The future is done. Result: " + future.get());
// 使用Promise设置异步任务的结果
Promise<Integer> promise = new Promise<>();
executor.submit(() -> {
Thread.sleep(1000);
promise.set(42);
});
System.out.println("Waiting for the promise...");
while (!promise.isCompleted()) {
Thread.sleep(100);
}
System.out.println("The promise is completed. Result: " + promise.get());
}
}
class Promise<T> implements Future<T> {
private final Object lock = new Object();
private T result;
private Throwable exception;
private boolean completed = false;
public void set(T result) {
synchronized (lock) {
if (!isDone()) {
this.result = result;
completed = true;
lock.notifyAll();
}
}
}
public void setException(Throwable exception) {
synchronized (lock) {
if (!isDone()) {
this.exception = exception;
completed = true;
lock.notifyAll();
}
}
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
throw new UnsupportedOperationException();
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
synchronized (lock) {
return completed;
}
}
@Override
public T get() throws InterruptedException, ExecutionException {
synchronized (lock) {
while (!isDone()) {
lock.wait();
}
if (exception != null) {
throw new ExecutionException(exception);
}
return result;
}
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
throw new UnsupportedOperationException();
}
}
在上面的示例中,我们使用了ExecutorService
来执行异步任务。
首先,我们使用Future
来获取异步任务的结果。我们通过executor.submit()
方法来提交一个任务,然后调用future.get()
方法来等待任务完成并获取其结果。
然后,我们使用Promise
来设置异步任务的结果。我们定义了一个Promise
类,它实现了Future
接口,并提供了set()
方法来设置任务的结果。我们通过executor.submit()
方法来提交一个任务,并在任务完成后调用promise.set()
方法来设置任务的结果。我们可以通过调用promise.get()
方法来等待任务完成并获取其结果。
需要注意的是,上面的Promise
实现只是一个简单的示例,它没有考虑线程安全和超时等问题。在实际应用中,需要根据具体情况来选择合适的Future
和Promise
实现,并对其进行适当的线程安全和错误处理。
CompletableFuture
在Java 8之前,Future接口的功能比较有限,只能用来获取异步任务的结果。
而在Java 8中引入了CompletableFuture
类,它实现了Future和Promise的功能,并提供了更强大的异步编程支持。
CompletableFuture类可以用来构建复杂的异步任务流水线,并提供了一系列的方法来处理任务的结果、异常和取消操作。
public class CompletableFuture<T> implements Future<T>, CompletionStage<T>
CompletableFuture从Future得到了对于异步结果的相关操作,比如get()、isDone()等
CompletableFuture从CompletionStage得到了对于异步任务的操作,比如thenApply、thenAccept、thenCompose等,用于定义异步任务完成后的处理逻辑
默认线程池ForkJoinPool
在不指定使用自定义线程池情况下,
CompletableFuture
中所有(用了线程池的)方法默认使用的线程池为ForkJoinPool
ForkJoinPool
是Java中提供的一个特殊的线程池,用于支持分而治之(分治法)的并行计算任务。它是ExecutorService
的一个具体实现,是一个基于工作窃取算法的线程池。专门用于执行ForkJoinTask
的任务。
ForkJoinPool
的特点和用途如下:
- 工作窃取(Work Stealing)算法: ForkJoinPool采用工作窃取算法,即线程可以从其他线程的任务队列中窃取任务执行。这种算法可以使得线程在任务处理完成后找到新的任务,提高线程的利用率和整体的并行性能。因此它非常适合用于执行大量的、相对短暂的任务。
- 分而治之的任务执行模型: ForkJoinPool特别适用于分而治之的任务。通过将大任务划分为更小的子任务进行并行处理,然后将子任务的结果合并,从而实现高效的并行计算。
- 工作线程的管理: ForkJoinPool会根据需要创建和回收工作线程,线程的数量可以动态地增长和减少,以适应任务的负载和系统资源的情况。
- 异步任务支持: ForkJoinPool不仅支持通过
fork()
和join()
方法执行分治任务,还支持通过submit()
方法提交异步任务,并通过Future
对象获取任务的执行结果。
使用ForkJoinPool
的步骤一般包括以下几个步骤:
- 创建
ForkJoinPool
对象,可以通过ForkJoinPool
的构造方法指定并行度(线程数量)。 - 创建一个继承自
RecursiveTask
或RecursiveAction
的任务类,实现任务的分解和合并逻辑。 - 在任务类中重写
compute()
方法,定义具体的任务逻辑。 - 创建任务对象,并通过调用
invoke()
或submit()
方法将任务提交给ForkJoinPool
执行。 - 最后,通过
join()
或get()
方法获取任务的执行结果。
需要注意的是,ForkJoinPool
适用于处理大规模的可分解任务,并行计算的效果取决于任务的划分和合并逻辑。因此,在使用ForkJoinPool
时,需要合理划分任务和设计任务的逻辑,以充分发挥其并行计算的优势。
ForkJoinPool.commonPool()
创建共享线程池
ForkJoinPool.commonPool()
是一个静态方法,用于获取一个共享的ForkJoinPool实例。
这个共享的ForkJoinPool是一个全局线程池,通常用于执行ForkJoin任务。它这个线程池会自适应地调整线程数量以处理任务,因此它非常适合用于执行大量的、相对短暂的任务。
具体来说,commonPool()
方法返回一个ForkJoinPool
实例,这个实例的线程数由Runtime.getRuntime().availableProcessors()
方法决定,它等于当前系统的CPU核心数。这是因为在大多数情况下,线程数量应该与CPU核心数量相匹配,以提高并行处理的效率。
commonPool()
方法返回的ForkJoinPool
实例还具有以下特点:
- 它是一个无界的线程池,当需要时可以创建新的线程。
- 它使用
WorkQueue
来存储任务,并使用工作窃取算法来调度线程执行任务。 - 它默认使用
ForkJoinPool.defaultForkJoinWorkerThreadFactory
作为工作线程的创建工厂,该工厂创建的线程都是daemon
线程。 - 它使用
ForkJoinPool.defaultUncaughtExceptionHandler
作为默认的未捕获异常处理器,用于处理工作线程中未捕获的异常。
总之,ForkJoinPool.commonPool()
返回的线程池是一个自适应的、基于工作窃取算法的线程池,它能够高效地处理大量的、相对短暂的任务。
ForkJoinPool
与ThreadPool
的不同
ForkJoinPool
适合用于以下场景:
- 任务是可以递归划分的,可以将大任务划分为更小的子任务。
- 任务之间的计算量差异较大,有些任务可能会比其他任务更耗时。
- 任务之间的依赖性较低,可以并行执行。
- 对于CPU密集型任务,ForkJoinPool可以更好地利用多核CPU的计算能力。
ThreadPool
适合用于以下场景:
- 需要处理大量的并发任务,但任务之间没有明显的递归划分。
- 任务之间的计算量相对均匀,没有明显的计算差异。
- 任务之间的依赖性较高,需要严格按照提交顺序执行。
- 对于I/O密集型任务,ThreadPool可以更好地利用线程等待I/O完成的时间。
需要根据具体的场景和需求来选择使用ForkJoinPool还是ThreadPool。ForkJoinPool适用于递归划分的任务和CPU密集型任务,而ThreadPool适用于大量并发任务和I/O密集型任务。如果任务之间的计算量差异大且可以并行执行,可以考虑使用ForkJoinPool,否则可以使用ThreadPool。
下面展示CompletableFuture
得具体使用方法
1.创建异步任务
带返回值的异步
supplyAsync
supplyAsync
是创建带有返回值的异步任务。它有如下两个方法,一个是使用默认线程池(ForkJoinPool.commonPool()
)的方法,一个是带有自定义线程池的重载方法
// 带返回值异步请求,默认线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
// 带返回值的异步请求,可以自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
System.out.println("do something....");
return "result";
});
//等待任务执行完成
System.out.println("结果->" + cf.get());
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 自定义线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
System.out.println("do something....");
return "result";
}, executorService);
//等待子任务执行完成
System.out.println("结果->" + cf.get());
}
测试结果
不带返回值的异步
runAsync
runAsync是创建没有返回值的异步任务。它有如下两个方法,一个是使用默认线程池(ForkJoinPool.commonPool()
)的方法,一个是带有自定义线程池的重载方法
// 不带返回值的异步请求,默认线程池
public static CompletableFuture<Void> runAsync(Runnable runnable)
// 不带返回值的异步请求,可以自定义线程池
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
System.out.println("do something....");
});
//等待任务执行完成
System.out.println("结果->" + cf.get());
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 自定义线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
System.out.println("do something....");
}, executorService);
//等待任务执行完成
System.out.println("结果->" + cf.get());
}
测试结果:
获取任务结果的方法
// 如果完成则返回结果,否则就抛出具体的异常
public T get() throws InterruptedException, ExecutionException
// 最大时间等待返回结果,否则就抛出具体异常
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
// 完成时返回结果值,否则抛出unchecked异常。为了更好地符合通用函数形式的使用,如果完成此 CompletableFuture所涉及的计算引发异常,则此方法将引发unchecked异常并将底层异常作为其原因
public T join()
// 如果完成则返回结果值(或抛出任何遇到的异常),否则返回给定的 valueIfAbsent。
public T getNow(T valueIfAbsent)
// 如果任务没有完成,返回的值设置为给定值
public boolean complete(T value)
// 如果任务没有完成,就抛出给定异常
public boolean completeExceptionally(Throwable ex)
2.异步回调
有入参有返回值的异步回调
thenApply
thenApply 表示某个任务执行完成后执行的动作,即回调方法,会将任务的执行结果(即方法返回值)作为入参传递到回调方法中,带有返回值。
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
return 1;
});
//cf2调用了cf1
CompletableFuture<Integer> cf2 = cf1.thenApply((result) -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
result += 2;
return result;
});
//等待任务1执行完成
System.out.println("cf1结果->" + cf1.get());
//等待任务2执行完成
System.out.println("cf2结果->" + cf2.get());
}
如上代码,cf1调用了自己的回调函数,并将自己的任务执行结果传入到回调函数中,给cf2使用
- 只有在cf1的任务执行完毕后,thenApplyAsync方法才会执行。也就是cf2会等待cf1完成后再完成自己的任务,但二者开始执行的先后顺序是不确定的(
cf2结果打印永远在cf1打印之后
) - 而且,thenApply方法是同步的,会用调用它的线程来执行,按照上面代码也就是主线程(
cf2与主线程是同一个
)
thenAcceptAsync
与thenApply
相同,都是异步回调,差异点在于:
- thenAcceptAsync不会用调用者线程执行,而是用新线程执行
- thenAcceptAsync可以使用自定义线程池,thenApply不可以
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+"main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
return 1;
});
CompletableFuture<Integer> cf2 = cf1.thenApplyAsync((result) -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
result += 2;
return result;
});
//等待任务1执行完成
System.out.println("cf1结果->" + cf1.get());
//等待任务2执行完成
System.out.println("cf2结果->" + cf2.get());
}
结果:
可以看到执行thenAcceptAsync的线程,不是主线程
有入参无返回值的异步回调
thenAccept
将执行结果即方法返回值作为入参传递到回调方法中,无返回值。同步,即与调用者公用一个线程。
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+"main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
return 1;
});
CompletableFuture<Void> cf2 = cf1.thenAccept((result) -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
});
//等待任务1执行完成
System.out.println("cf1结果->" + cf1.get());
//等待任务2执行完成
System.out.println("cf2结果->" + cf2.get());
}
结果:
thenAcceptAsync
与thenAccept
基本一致。不同在于它是异步,而且可以自定义线程池
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+"main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
return 1;
});
CompletableFuture<Void> cf2 = cf1.thenAcceptAsync((result) -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
});
//等待任务1执行完成
System.out.println("cf1结果->" + cf1.get());
//等待任务2执行完成
System.out.println("cf2结果->" + cf2.get());
}
结果:
无入参无返回值的异步回调
thenRun
无入参,无返回值。同步,与调用者共用一个线程。
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+"main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
return 1;
});
CompletableFuture<Void> cf2 = cf1.thenRun(() -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
});
//等待任务1执行完成
System.out.println("cf1结果->" + cf1.get());
//等待任务2执行完成
System.out.println("cf2结果->" + cf2.get());
}
结果:
thenRunAsync
无入参,无返回值。异步,不与调用者共用一个线程,会开启新的。可使用自定义线程池。
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+"main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
return 1;
});
CompletableFuture<Void> cf2 = cf1.thenRunAsync(() -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
});
//等待任务1执行完成
System.out.println("cf1结果->" + cf1.get());
//等待任务2执行完成
System.out.println("cf2结果->" + cf2.get());
}
结果:
有异常无返回值的异步回调
whenComplete
可以将执行结果或者执行期间抛出的异常传递给回调方法,如果发生异常,回调函数内的获取的执行结果为null,而且不能再外部用get方法获取,否则会报错。
需要注意,此回调方法是同步的,也就是用它的调用者线程执行
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+" main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
int a = 1/0;
return 1;
});
CompletableFuture<Integer> cf2 = cf1.whenComplete((result, e) -> {
System.out.println("上个任务结果:" + result);
System.out.println("上个任务抛出异常:" + e);
System.out.println(Thread.currentThread() + " cf2 do something....");
});
// //等待任务1执行完成
// System.out.println("cf1结果->" + cf1.get());
// //等待任务2执行完成
// System.out.println("cf2结果->" + cf2.get());
}
结果:
可以看到执行回调的是主线程(调用者线程),并输出异常信息且结果为null
如果放开注解进行get,
System.out.println("cf1结果->" + cf1.get());
System.out.println("cf2结果->" + cf2.get());
则会:
两个get都会报错,因为任务都报错了,回调肯定也报错
whenCompleteAsync
与whenComplete
基本一致,不同点在于whenCompleteAsync会开启新线程执行,并且可使用自定义线程池
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+" main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
int a = 1/0;
return 1;
});
CompletableFuture<Integer> cf2 = cf1.whenCompleteAsync((result, e) -> {
System.out.println("上个任务结果:" + result);
System.out.println("上个任务抛出异常:" + e);
System.out.println(Thread.currentThread() + " cf2 do something....");
});
// //等待任务1执行完成
// System.out.println("cf1结果->" + cf1.get());
// //等待任务2执行完成
// System.out.println("cf2结果->" + cf2.get());
}
结果:
有异常有返回值的异步回调
handle
相比whenComplete
,也会传递异常,但是有返回值。同步。
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+"main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
int a = 1/0;
return 1;
});
CompletableFuture<Integer> cf2 = cf1.handle((result, e) -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
System.out.println("上个任务结果:" + result);
System.out.println("上个任务抛出异常:" + e);
return result+2;
});
// System.out.println("cf2结果->" + cf1.get());
// //等待任务2执行完成
// System.out.println("cf2结果->" + cf2.get());
}
结果:
handleAsync
相比whenCompleteAsync
,也会传递异常,但是有返回值。异步。可自定义线程池。
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+"main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
int a = 1/0;
return 1;
});
CompletableFuture<Integer> cf2 = cf1.handleAsync((result, e) -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
System.out.println("上个任务结果:" + result);
System.out.println("上个任务抛出异常:" + e);
return result+2;
});
// System.out.println("cf2结果->" + cf1.get());
// //等待任务2执行完成
// System.out.println("cf2结果->" + cf2.get());
}
结果:
3.多任务组合处理
两个任务组合全部完成
thenCombine
、thenAcceptBoth
和runAfterBoth
这三个方法都是将两个CompletableFuture组合起来处理,只有两个任务都正常完成时,才进行下阶段任务。
注意两个任务中只要有一个执行异常,则将该异常信息作为指定任务的执行结果。
thenCombine 有返回值
将两个任务的执行结果作为所提供函数的参数,且该方法有返回值。
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+" main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
return 1;
});
CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
return 2;
});
CompletableFuture<Integer> cf3 = cf1.thenCombine(cf2, (a, b) -> {
System.out.println(Thread.currentThread() + " cf3 do something....");
return a + b;
});
System.out.println("cf3结果->" + cf3.get());
}
结果:
Thread[main,5,main] main thread....
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf1 do something....
Thread[ForkJoinPool.commonPool-worker-2,5,main] cf2 do something....
Thread[main,5,main] cf3 do something....
cf3结果->3
thenAcceptBoth 无返回值
thenAcceptBoth同样将两个任务的执行结果作为方法入参,但是无返回值
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+"main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
return 1;
});
CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
return 2;
});
CompletableFuture<Void> cf3 = cf1.thenAcceptBoth(cf2, (a, b) -> {
System.out.println(Thread.currentThread() + " cf3 do something....");
System.out.println("a+b:"+(a + b));
});
System.out.println("cf3结果->" + cf3.get());
}
结果:
Thread[main,5,main]main thread....
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf1 do something....
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf2 do something....
Thread[main,5,main] cf3 do something....
a+b:3
cf3结果->null
runAfterBoth 没有入参,也没有返回值
没有入参,也没有返回值
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+"main thread....");
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
return 1;
});
CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
return 2;
});
CompletableFuture<Void> cf3 = cf1.runAfterBoth(cf2, () -> {
System.out.println(Thread.currentThread() + " cf3 do something....");
});
System.out.println("cf3结果->" + cf3.get());
}
结果:
Thread[main,5,main]main thread....
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf1 do something....
Thread[ForkJoinPool.commonPool-worker-2,5,main] cf2 do something....
Thread[main,5,main] cf3 do something....
cf3结果->null
两个任务组合任一完成
applyToEither
、acceptEither
和runAfterEither
。这三个方法都是将两个CompletableFuture组合起来处理,当有一个任务正常完成时,就会进行下阶段任务。
注意两个任务中只要有一个执行异常,则将该异常信息作为指定任务的执行结果。
thenCombine 有返回值
会将两个任务的执行结果作为所提供函数的参数,且该方法有返回值
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+" main thread....");
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf1 do something....");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "cf1 任务完成";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf2 do something....");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "cf2 任务完成";
});
CompletableFuture<String> cf3 = cf1.applyToEither(cf2, (result) -> {
System.out.println("接收到" + result);
System.out.println(Thread.currentThread() + " cf3 do something....");
return "cf3 任务完成";
});
System.out.println("cf3结果->" + cf3.get());
}
结果:
cf1完成后,cf3就完成了,不等cf2
Thread[main,5,main] main thread....
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf1 do something....
Thread[ForkJoinPool.commonPool-worker-2,5,main] cf2 do something....
接收到cf1 任务完成
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf3 do something....
cf3结果->cf3 任务完成
acceptEither 无返回值
acceptEither同样将已经完成任务的执行结果作为方法入参,但是无返回值
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+" main thread....");
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf1 do something....");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "cf1 任务完成";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf2 do something....");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "cf2 任务完成";
});
CompletableFuture<Void> cf3 = cf1.acceptEither(cf2, (result) -> {
System.out.println("接收到" + result);
System.out.println(Thread.currentThread() + " cf3 do something....");
});
System.out.println("cf3结果->" + cf3.get());
}
结果:
cf1完成后,cf3就完成了,不等cf2,而且cf3为null,证明没有返回值
Thread[main,5,main] main thread....
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf1 do something....
Thread[ForkJoinPool.commonPool-worker-2,5,main] cf2 do something....
接收到cf1 任务完成
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf3 do something....
cf3结果->null
runAfterEither 没有入参,也没有返回值
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+" main thread....");
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf1 do something....");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cf1 任务完成");
return "cf1 任务完成";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf2 do something....");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cf2 任务完成");
return "cf2 任务完成";
});
CompletableFuture<Void> cf3 = cf1.runAfterEither(cf2, () -> {
System.out.println(Thread.currentThread() + " cf3 do something....");
System.out.println("cf3 任务完成");
});
System.out.println("cf3结果->" + cf3.get());
}
结果:
Thread[main,5,main] main thread....
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf1 do something....
Thread[ForkJoinPool.commonPool-worker-2,5,main] cf2 do something....
cf1 任务完成
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf3 do something....
cf3 任务完成
cf3结果->null
两个任务组合全部完成
allOf
多个CompletableFuture任务组合,都执行完成后才会执行。
只要有一个任务执行异常,返回的CompletableFuture执行get方法就会抛出异常,如果都是正常执行,则get返回null
。
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+" main thread....");
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf1 do something....");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cf1 任务完成");
return "cf1 任务完成";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf2 do something....");
//int a = 1/0; //如果放开,在cf1、cf3任务完成后会报错
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cf2 任务完成");
return "cf2 任务完成";
});
CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf2 do something....");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cf3 任务完成");
return "cf3 任务完成";
});
//组合3个任务
CompletableFuture<Void> cfAll = CompletableFuture.allOf(cf1, cf2, cf3);
System.out.println("cfAll结果->" + cfAll.get());
}
结果:
Thread[main,5,main] main thread....
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf1 do something....
Thread[ForkJoinPool.commonPool-worker-2,5,main] cf2 do something....
Thread[ForkJoinPool.commonPool-worker-3,5,main] cf2 do something....
cf1 任务完成
cf3 任务完成
cf2 任务完成
cfAll结果->null
如果放开cf2的int a = 1/0
,则结果为
Thread[main,5,main] main thread....
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf1 do something....
Thread[ForkJoinPool.commonPool-worker-2,5,main] cf2 do something....
Thread[ForkJoinPool.commonPool-worker-3,5,main] cf2 do something....
cf1 任务完成
cf3 任务完成
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1908)
at com.ruoyi.Test.main(Test.java:53)
Caused by: java.lang.ArithmeticException: / by zero
at com.ruoyi.Test.lambda$main$1(Test.java:31)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1604)
at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1596)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1067)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1703)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:172)
两个任务组合任一完成
anyOf
多个CompletableFuture任务组合,只要有一个任务执行完成,anyOf就会执行
只要有一个任务有异常,则返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回执行完成任务的结果
。
测试代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread()+" main thread....");
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf1 do something....");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cf1 任务完成");
return "cf1 任务完成";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf2 do something....");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cf2 任务完成");
return "cf2 任务完成";
});
CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf2 do something....");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cf3 任务完成");
return "cf3 任务完成";
});
CompletableFuture<Object> cfAll = CompletableFuture.anyOf(cf1, cf2, cf3);
System.out.println("cfAll结果->" + cfAll.get());
}
结果:
cf1设置睡眠时间最短,返回cf1
Thread[main,5,main] main thread....
Thread[ForkJoinPool.commonPool-worker-1,5,main] cf1 do something....
Thread[ForkJoinPool.commonPool-worker-2,5,main] cf2 do something....
Thread[ForkJoinPool.commonPool-worker-3,5,main] cf2 do something....
cf1 任务完成
cfAll结果->cf1 任务完成
Spring框架应用点
在Spring 5.0版本中,增加了对Java 8中
CompletableFuture
的支持。具体地,Spring框架在以下几个地方用到了CompletableFuture:
- @Async注解:@Async注解在异步方法调用时,返回的值类型可以是CompletableFuture,表示异步方法执行的结果。这样,异步方法的调用方可以通过CompletableFuture来获取异步方法的执行结果。
- WebFlux:WebFlux是Spring框架中的响应式编程模型。在WebFlux中,可以通过Mono和Flux来表示异步结果。其中,Mono表示异步单值结果,而Flux表示异步多值结果。Mono和Flux都是基于CompletableFuture实现的,提供了更加方便的异步操作和响应式编程能力。
- Spring Data:Spring Data是Spring框架中的数据访问层。在Spring Data中,可以通过CompletableFuture来实现异步的数据访问操作,提高了系统的并发处理能力。
总之,Spring框架中对CompletableFuture的支持,可以帮助开发者更加方便地实现异步操作和响应式编程,提高系统的并发性能和吞吐量。