目录
1、异步
01、初始化线程的4种方式
创建线程的4种方式
-
1、继承
Thread
-
2、实现
Runnable
接口 -
3、实现
Callable
接口+FutureTask
(可以拿到返回结果,可以处理异常) -
4、
线程池
给线程池直接提交任务:
service.execute(new Runnable01())
;
提交任务的两种方式:
- 1)、
submit
可以获取任务的返回值 - 2)、
executors
不获取任务的返回值(只是执行)
总结
我们以后再业务代码里面,以上三种启动线程的方式都不用。将所有的多线程异步任务都交给线程池执行
区别
继承Thread
、实现Runnable
不能得到返回值。实现Callable
可以获取返回值
继承Thread
、实现Runnable
、实现Callable
都不能控制资源,可能导致服务器资源耗尽
线程池
可以控制资源,性能稳定。
- 测试代码
// 测试线程池
public class ThreadTest {
//4、线程池
//创建一个固定数量的线程池 此处为创建10个
/* 系统中池只有一两个,每个异步任务,提交给线程池让它去执行 */ //此处为只有一个池
public static ExecutorService service = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main ... start ...");
//1、继承Thread
// Thread01 thread1 = new Thread01();
// thread1.start(); //启动线程
/***
* main ... start ...
* main ... end ...
* 当前线程:11
* 运行结果:5
*/
//2、实现Runnable
// Runable01 runable01 = new Runable01();
// new Thread(runable01).start();
/***
* main ... start ...
* main ... end ...
* 当前线程:11
* 运行结果:5
*/
//3、实现Callable接口+FutureTask
// FutureTask<Integer> task = new FutureTask<>(new Callable01());
// new Thread(task).start();
/***
* main ... start ...
* main ... end ...
* 当前线程:11
* 运行结果:5
*/
//3.1)、等待整个线程执行完成,获取返回结果 -> 阻塞等待
// Integer integer = task.get();
// System.out.println("返回结果:" + integer);
/***
* 可以看到两个执行顺序不一样,使用get()方法需等待task线程执行结束,才可以执行main线程
* main ... start ...
* 当前线程:11
* 运行结果:5
* 返回结果:5
* main ... end ...
*/
//4、创建好线程池之后,使用线程池【线程池方式】
//4.1)、给线程池提交任务
// service.submit(); //可以获取任务的返回值
service.execute(new Runable01()); //不获取任务的返回值(只是执行)
/***
* main ... start ...
* main ... end ...
* 当前线程:11
* 运行结果:5
*/
System.out.println("main ... end ...");
}
//1、继承Thread
public static class Thread01 extends Thread{
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果:" + i);
}
}
//2、实现Runnable
public static class Runable01 implements Runnable{
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果:" + i);
}
}
//3、实现Callable接口+FutureTask
//需要指定泛型。泛型就是方法的返回值类型。
public static class Callable01 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果:" + i);
return i;
}
}
}
02、线程池
创建线程池方式2:【须传入线程池的7大参数】
ThreadPoolExecutor executor = new ThreadPoolExecutor();
线程池的7大参数
参数 | 说明 | 作用及解释 |
---|---|---|
corePoolSize | 核心线程数 | 线程池,创建好以后就准备就绪的线程数量,就等待接收异步任务去执行 【只要线程池不销毁,就会一直存在,除非设置了 allowCoreThreadTimeOut (允许核心线程池超时)】 示例:5个 Thread thread = new Thread(); thread.start(); |
maximumPoolSize | 最大线程数量 | 控制资源 |
keepAliveTime | 存活时间 | 如果当前正在运行的线程数量大于core数量 释放空闲的线程(maximumPoolSize-corePoolSize)。只要线程空闲大于指定的keepAliveTime; |
unit | 时间单位 | |
BlockingQueue workQueue | 阻塞队列 | 如果任务有很多。就会将多的任务放在队列里面 只要有线程空闲,就会去队列里面取出新的任务继续执行 示例:new LinkedBlockingQueue<>(),默认是Integer的最大值。可能导致内存不够,需要传入压力测试后的定制数量 |
ThreadFactory | 线程创建的工厂 | |
RejectedExecutionHandler handler | 处理队列满了的情况 | 如果队列满了,按照我们指定的拒绝策略,拒绝执行 |
执行流程
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5,
200,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
说明:
- 线程池创建,准备好core数量的核心线程,准备接受任务
- core满了,就将再进来的任务放入阻塞队列中。空闲的core就会自己去阻塞队列获取任务执行
- 阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量
- max都执行完成,(max-core)数量空闲的线程会在keepAliveTime指定的时间后,自动销毁,释放空闲的线程。最终保持到core的大小
- 如果线程开到了max数量,还有新任务进来,就会使用RejectedExecutionHandler拒绝任务
示例:
一个线程池 core 7, max 20, queue 50, 100并发进来怎么分配的?
- 7个会立即执行。
- 50个进入队列。
- 队列满了可以再开启线程,再开13【max-core】个进行执行。
- 剩下30个就是用拒绝策略,拒绝策略一般都是丢弃,如果不想丢弃还要执行,可以使用CallerRunsPolicy策略
常见的4种线程池
线程池 | 说明 |
---|---|
newCachedThreadPool | 创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 core是0,所有都可以回收 |
newFixedThreadPool | 创建一个固定大小线程池,可控制线程最大并发数,超出的线程会在队列中等待。core=max,都不可回收 |
newScheduledThreadPool | 定时任务的线程池 |
newSingleThreadExecutor | 创建一个单线程化的线程池,后台从队列里面获取任务,挨个执行 |
2、CompletableFuture
异步编排
01、创建异步对象
CompletableFuture
提供了4个静态方法来创建异步对象
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
runAsync
()无返回值。supplyAsync
()有返回值。
没有指定Executor
的方法会使用ForkJoinPool.commonPool()
作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同。
可以传入自定义的线程池。不指定线程池的话会使用默认的线程池
- 示例
public class ThreadTest {
//创建一个固定数量的线程池 此处为创建10个
public static ExecutorService execute = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main ... start ...");
//1、runAsync()方法
// CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
// System.out.println("当前线程:" + Thread.currentThread().getId());
// int i = 10 / 2;
// System.out.println("运行结果:" + i);
// }, execute);
/***
* main ... start ...
* main ... end ...
* 当前线程:11
* 运行结果:5
*/
//2、supplyAsync方法
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, execute);
System.out.println("返回值 = " + future.get());
/***
* main ... start ...
* 当前线程:11
* 运行结果:5
* 返回值 = 5
* main ... end ...
*/
System.out.println("main ... end ...");
}
}
02、计算结果完成时的回调方法
当CompletableFuture的计算结果完成,或者抛出异常的时候,可以执行特定的Action。主要是下面的方法:
//可以处理异常,无返回值,当前一个线程成功执行之后,还可以做别的事情,但是这个线程还是和前一个线程一样
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
//可以处理异常,无返回值,当前一个线程成功执行之后,还可以做别的事情,还是以异步的方式交给线程池进行处理
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
//可以处理异常,有返回值
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)
- 示例
public class ThreadTest {
//创建一个固定数量的线程池 此处为创建10个
public static ExecutorService execute = Executors.newFixedThreadPool(10);
/***
* 方法执行完成后的感知
*/
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main ... start ...");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;
//传入的两个参数: result:结果 exception:异常
}, execute).whenComplete((result,exception) -> {
//虽然可以感知异常信息。但是无法返回数据(类似于监听器)
System.out.println("异步任务为执行成功......结果是:"+ result + ",异常是:"+ exception);
}).exceptionally(throwable -> {
//可以感知异常信息。同时可以返回默认值
return 10;
});
System.out.println("返回值 = " + future.get()); //此处因为异常返回的是定义的异常返回默认值
System.out.println("main ... end ...");
}
}
- 输出
main ... start ...
当前线程:11
异步任务为执行成功......结果是:null,异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
返回值 = 10
main ... end ...
03、handle 方法 -> 最终处理
handle():可以对执行返回的结果进行进一步处理并返回自定义值
- 示例
public class ThreadTest {
//创建一个固定数量的线程池 此处为创建10个
public static ExecutorService execute = Executors.newFixedThreadPool(10);
/***
* 方法执行完成后的处理
*/
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main ... start ...");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;
//传入的两个参数: result:结果 thr:异常
}, execute).handle((result,thr) -> {
if (result != null){
return result * 2;
}
if (thr != null){
return 0;
}
return 1;
});
System.out.println("返回值 = " + future.get());
System.out.println("main ... end ...");
}
}
- 输出
main ... start ...
当前线程:11
返回值 = 0
main ... end ...
04、线程串行化
//不能接收上一步的执行结果,无返回值
public CompletableFuture<Void> thenRun(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action, Executor executor)
//能接收上一步结果,并消费处理该结果,无返回值
public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)
//能接收上一步结果,并消费处理该结果,有返回值
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
- T:上一个任务返回结果的类型
- U:当前任务的返回值类型
- 带有Async默认是异步执行的。这里所谓的异步指的是不在当前线程内执行。
- 测试
thenRun
不能接收上一步的执行结果,无返回值
public class ThreadTest {
//创建一个固定数量的线程池 此处为创建10个
public static ExecutorService execute = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main ... start ...");
//串行化
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println("运行结果:" + i);
return i;
}, execute).thenRunAsync(() -> {
System.out.println("任务2启动了......");
}, execute);
System.out.println("返回值 = " + future.get());
System.out.println("main ... end ...");
}
}
- 输出
main ... start ...
当前线程:11
运行结果:2
任务2启动了......
返回值 = null //无返回值
main ... end ...
- 测试
thenAccept
能接收上一步结果,并消费处理该结果,无返回值
public class ThreadTest {
//创建一个固定数量的线程池 此处为创建10个
public static ExecutorService execute = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main ... start ...");
//串行化
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println("运行结果:" + i);
return i;
}, execute).thenAcceptAsync((result) -> {
System.out.println("任务2启动了......");
System.out.println("result = " + result);
}, execute);
System.out.println("返回值 = " + future.get());
System.out.println("main ... end ...");
}
}
- 输出
main ... start ...
当前线程:11
运行结果:2
任务2启动了......
result = 2 //接收上一步的结果
返回值 = null //无返回值
main ... end ...
- 测试
thenApply
能接收上一步结果,并消费处理该结果,有返回值
public class ThreadTest {
//创建一个固定数量的线程池 此处为创建10个
public static ExecutorService execute = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main ... start ...");
//串行化
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println("运行结果:" + i);
return i;
}, execute).thenApplyAsync((result) -> {
System.out.println("任务2启动了......");
System.out.println("result = " + result);
return "Hello" + result;
}, execute);
System.out.println("返回值 = " + future.get());
System.out.println("main ... end ...");
}
}
- 输出
main ... start ...
当前线程:11
运行结果:2
任务2启动了......
result = 2 //接收上一步的结果
返回值 = Hello2 //有返回值
main ... end ...
05、两任务组合 - 都要完成
以下方法的触发条件:--->之前的两个任务都完成,才开始执行合并任务。A&&B==1-->执行C的关系
//runAfterBoth:不获取future结果,没有返回值
public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor);
//thenAcceptBoth:获取两个future任务的结果,没有返回值
public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action,Executor executor);
//thenCombine:获取两个future任务的结果,有返回值
public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);
- 示例
public class ThreadTest {
//创建一个固定数量的线程池 此处为创建10个
public static ExecutorService execute = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main ... start ...");
//任务1
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1线程启动...... 当前线程:" + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println("任务1线程结束...... 运行结果:" + i);
return i;
}, execute);
//任务2
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2线程启动...... 当前线程:" + Thread.currentThread().getId());
System.out.println("任务2线程结束......");
return "Hello";
}, execute);
//合并任务插入的位置..................
System.out.println("返回值 = " + future.get());
System.out.println("main ... end ...");
}
}
runAfterBoth
:不获取future结果,没有返回值
//合并任务1
CompletableFuture<Void> future = future01.runAfterBothAsync(future02, () -> {
System.out.println("任务3开始......");
}, execute);
- 输出
main ... start ...
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务2线程结束......
任务3开始......
返回值 = null //没有返回值
main ... end ...
thenAcceptBoth
:获取两个future任务的结果,没有返回值
//合并任务2 f1 和 f2 分别是 future01 和 future02 的返回值
CompletableFuture<Void> future = future01.thenAcceptBothAsync(future02, (f1, f2) -> {
System.out.println("任务3开始...... 接收的结果分别是:" + f1 +" --> " + f2);
}, execute);
- 输出
main ... start ...
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务2线程结束......
任务3开始...... 接收的结果分别是:2 --> Hello //接收前两个任务的结果
返回值 = null //没有返回值
main ... end ...
thenCombine
:获取两个future任务的结果,有返回值
//合并任务3 f1 和 f2 分别是 future01 和 future02 的返回值
CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
System.out.println("任务3开始...... 接收的结果分别是:" + f1 + " --> " + f2);
return f1 + " : " + f2;
}, execute);
- 输出
main ... start ...
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务2线程结束......
任务3开始...... 接收的结果分别是:2 --> Hello //接收前两个任务的结果
返回值 = 2 : Hello //有返回值
main ... end ...
06、两个任务组合 - 一个完成
以下方法的触发条件:--->之前的两个任务任意完成一个,就开始执行合并任务。A||B==1-->执行C的关系
//runAfterEither:不获取future结果,没有返回值
public CompletionStage<Void> runAfterEither(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);
//acceptEither:获取完成了的那个future的结果,没有返回值
public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action);
public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action);
public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action,Executor executor);
//applyToEither:获取完成了的那个future的结果,并且有返回值
public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn);
public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn);
public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn,Executor executor);
- 示例
- 为了让示例效果明显,让任务2睡眠3s才执行任务2结束的语句
- 注意方法1和方法2的返回值类型应该统一,此处都用Object
- 接收返回值只接收一个,为执行完毕的那个方法的返回值
public class ThreadTest {
//创建一个固定数量的线程池 此处为创建10个
public static ExecutorService execute = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
//任务1
CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1线程启动...... 当前线程:" + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println("任务1线程结束...... 运行结果:" + i);
return i;
}, execute);
//任务2
CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2线程启动...... 当前线程:" + Thread.currentThread().getId());
try {
Thread.sleep(3000);
System.out.println("任务2线程结束......");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello";
}, execute);
//合并任务插入的位置..................
System.out.println("返回值 = " + future.get());
System.out.println("main ... end ...");
}
}
runAfterEither
:不获取future结果,没有返回值
//合并任务1
CompletableFuture<Void> future = future01.runAfterEitherAsync(future02, () -> {
System.out.println("任务3开始......");
}, execute);
- 输出
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务3开始...... //任务3提前执行
返回值 = null // 没有返回值
main ... end ...
任务2线程结束......
acceptEither
:获取完成了的那个future的结果,没有返回值
//合并任务2
CompletableFuture<Void> future = future01.acceptEitherAsync(future02, (result) -> {
System.out.println("任务3开始...... 执行完成的方法的结果是:" + result);
}, execute);
- 输出
main ... start ...
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务3开始...... 执行完成的方法的结果是:2 //方法1先运行完毕,其返回值为2,且任务3提前执行
返回值 = null //没有返回值
main ... end ...
任务2线程结束......
applyToEither
:获取完成了的那个future的结果,并且有返回值
//合并任务3
CompletableFuture<String> future = future01.applyToEitherAsync(future02, (result) -> {
System.out.println("任务3开始...... 执行完成的方法的结果是:" + result);
return result.toString() + "--> 乌拉";
}, execute);
- 输出
main ... start ...
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务3开始...... 执行完成的方法的结果是:2 //任务1先运行完毕,其返回值为2,且任务3提前执行
返回值 = 2--> 乌拉 //有返回值
main ... end ...
任务2线程结束......
07、多任务组合
//allOf:等待所有任务完成
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
//anyOf:只需要其中一个任务完成
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
- 示例
- 需要任务1、任务2、任务3 依次执行
- 为了让示例效果明显,让任务2睡眠3s才执行打印语句
- 记得一定要执行get()或join()方法
allOf
:等待所有任务完成
public class ThreadTest {
//创建一个固定数量的线程池 此处为创建10个
public static ExecutorService execute = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
//任务1
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品的图片信息");
return "hello.jpg";
},execute);
//任务2
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("查询商品的属性信息");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "黑色 256GB";
},execute);
//任务3
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品的介绍");
return "华为 P40";
},execute);
//多任务组合allOf()
CompletableFuture<Void> future = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
future.get(); //等待结果完成
// future.join(); //使用join也可以
System.out.println("之前任务的返回值 = " + futureImg.get() + " -> " + futureAttr.get() + " -> " + futureDesc.get());
System.out.println("返回值 = " + future.get());
System.out.println("main ... end ...");
}
}
- 输出结果
main ... start ...
查询商品的图片信息
查询商品的属性信息 //顺序执行
查询商品的介绍
之前任务的返回值 = hello.jpg -> 黑色 256GB -> 华为 P40 //可以获取之前任务的返回值
返回值 = null //方法返回值为空
main ... end ...
注意:不加
get()或者join()的话,会发现执行顺序不对
anyOf
:只需要其中一个任务完成- 不要去使用之前任务的返回值,因为get()是阻塞方法,会阻塞使得前3个任务都执行完成
public class ThreadTest {
//创建一个固定数量的线程池 此处为创建10个
public static ExecutorService execute = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
//任务1
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品的图片信息");
return "hello.jpg";
},execute);
//任务2
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("查询商品的属性信息");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "黑色 256GB";
},execute);
//任务3
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品的介绍");
return "华为 P40";
},execute);
//多任务组合anyof()
CompletableFuture<Object> future = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
// future.get(); //等待结果完成
// future.join();
// System.out.println("之前任务的返回值 = " + futureImg.get() + " -> " + futureAttr.get() + " -> " + futureDesc.get()); //这一行不要用了
System.out.println("返回值 = " + future.get());
System.out.println("main ... end ...");
}
}
- 输出
main ... start ...
查询商品的图片信息 //第一个任务执行后,后面的任务就不需要执行了
返回值 = hello.jpg //返回最先执行任务的返回值
main ... end ...
查询商品的介绍
查询商品的属性信息