为了节约时间和提高吞吐量,我们要做一些异步请求
1,继承Thread
2,实现Runnable接口
3,实现Callable接口+FutureTask(可以拿到返回结果,可以处理异常)
4,线程池
方式1和方式2:主线程无法获取线程的运算结果。不适合当前场景
方式3:主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。可以导致服务器资源耗尽
方式4:通过如下两种方式初始化线程池
Executors.newFiexedThreadPool(3);
//或者
new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit,unit,workQueue,threadFactory,handler)
通过线程池性能稳定,也可以获取执行结果,并捕获异常。但是,在业务复杂情况下,一个异步调用可能会依赖于另一个异步调用的执行结果。
方式一实现代码如下:
1,继承Thread
public class ThreadTest {
public static void main(String[] args) {
System.out.println("main....start....");
Thread01 thread01 = new Thread01();
thread01.start();//启动线程
System.out.println("main....end....");
}
public static class Thread01 extends Thread{
@Override
public void run() {
System.out.println("当前线程: "+Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果: "+i);
}
}
}
main....start....
main....end....
当前线程:12
运行结果:5
方式二实现代码如下
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);
}
}
main方法中
System.out.println("main....start....");
Runable01 runable01 = new Runable01();
new Thread(runable01).start();
System.out.println("main....end....");
main....start....
main....end....
当前线程:12
运行结果:5
第三种方式
public static class Callable01 implements Callable{
@Override
public Object call() throws Exception {
System.out.println("当前线程: "+Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果: "+i);
return i;
}
}
main方法中
FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
new Thread(futureTask).start();
System.out.println("main....end....");
可以看到Callable接口中直接结束了
所以我们将采取FutureTask的方式来启动Callable的线程,根据FutureTask源码
继而new出来返回FutureTask,FutureTask又继承RunnableFuture,而RunnableFuture又分别继承Runnable,Future
所以它的启动方式就是FutureTask futureTask = new FutureTask<>(new Callable01());new Thread(futureTask).start();
运行结果如下
main....start....
main....end....
当前线程:12
运行结果:5
Callable最大的好处是FutureTask 我们假设后台运行的很慢,我们还希望后台返回这个Callable的计算结果,就可以使用FutureTask ,它有一个方法.get
等异步方法执行完,返回它的结果
Integer integer = futureTask.get();
//等待整个线程执行完成,获取返回结果
修改main方法
Integer integer = futureTask.get();
System.out.println("main....end...."+integer);
main....start....
当前线程:12
运行结果:5
main....end....+5
所以Integer integer = futureTask.get();是一个阻塞等待
futureTask不仅可以接受Callable,还接受Runnable,如果是Runnable,还可以传一个对象,让这个对象接受参数
第四种方式
给线程池直接提交任务。
为什么使用线程池?如果我们后来的项目中异步比较多,每次都进行原生代码new Thread().start(),没执行一个线程就开启一个start(存在问题)
我们以后在业务代码里,以上三种启动线程的方式都不能用 避免大量new Thread造成资源消耗完,应该将所有的多线程异步任务交给线程池执行
JUC中最快得到线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//10代表有十个空闲线程 当前系统中池只有一两个,每个异步任务,提交给线程让他自己去执行就行
并不应该是每运行一次就创建一个线程池,应该是一个线程池,大家将所有任务都交给这个线程池来处理
要想访问线程池
public static ExecutorService executorService = Executors.newFixedThreadPool(10);
里面有submit,可以将一个Runnable或Callable的任务,或者使用execute让它执行
submit跟execute两个区别
如果是submit给线程池中添加一个任务,我们可以获取任务的返回值;如果是execute,直接让线程池执行我们这个操作,返回类型是void 都是给线程池提交异步请求
main中执行
executorService.execute(new Runable01());
main....start....
main....end....
当前线程:12
运行结果:5
这是我们将任务提交给线程池,而不是我们自己在new
给线程池直接提交任务。
* executorService.execute(new Runable01());
* 1,创建
* 1)Executors
* 2)new ThreadPoolExecutor();
* Future:可以获得到异步结果
*
* 区别
* 1,2不能获取返回值3可以获取返回值
* 1,2,3都不能控制资源
* 4,可以控制资源,性能稳定
*
*/
/**
* int corePoolSize【5】, 我们的线程数量总是在池中保持着 就算系统当前是空闲的,也是在池总一直有的,等待接收新任务的 除非设置allowCoreThreadTimeOut(允许核心线程超时,这样核心线程空闲就被回收了,否则就不回收)
* 核心线程数[一直存在除非设置allowCoreThreadTimeOut] 线程池 创建好以后准备就绪的线程数量,就等待来接受异步任务去执行 5个 Thread thread = new Thread() thread.start()
int maximumPoolSize, 相当于线程池最大数量;控制资源并发
long keepAliveTime,存活时间 如果当前我们线程数量大于核心线程数的时候 释放空闲线程(maximumPoolSize-corePoolSize) 只要线程空闲大于指定keepAliveTime
TimeUnit unit, 时间单位
BlockingQueue<Runnable> workQueue,阻塞队列 如果任务有很多,就会将目前多的任务放在队列里面 只要有线程空闲,就会去队列里面取出新的任务继续执行
ThreadFactory threadFactory, 线程的创建工厂
RejectedExecutionHandler handler 如果队列满了,按照我们指定的拒绝策略拒绝执行任务(默认使用丢弃策略AbortPolicy)
工作顺序:
1)线程池创建好,准备好core数量的核心线程,准备接受任务
1.1core满了,就将再进来的任务放到阻塞队列中,空闲的core就会自己去阻塞队列获取任务执行
1.2阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量
1.3max满了就用拒绝策略RejectedExecutionHandler拒绝任务
1.4max都执行完成,有很多空闲 在指定的时间【keepAliveTime】以后,释放max-core这些线程
new LinkedBlockingDeque<>():默认是Integer的最大值。内存不够
*/
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,
200,
10,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(100000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
默认ThreadFactory
拒绝策略(默认使用丢弃策略AbortPolicy)
一个简单面试题:
一个线程池core7 max20 queue 50 100并发进来怎么分配
首先 7个会立即得到执行 50个进入队列 再开13个进行执行 剩下30个采用拒绝策略
如果不想抛弃还要执行 CallerRunsPolicy;同步方法 也可以尝试使用抛弃以前老数据
newCachedThreadPool() core是0,所有都可以回收
创建一个可缓存线程池,如果线程池长度超过处理需求,可灵活回收空闲线程,若无可回收,则新建线程
newFixedThreadPool() 固定大小 core=max 都不可被回收
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
newScheduledThreadPool() 定时任务线程池
创建一个定长线程池,支持定时及周期性任务执行
newSingleThreadExecutor() 单线程的线程池,后台从队列里面获取任务 挨个执行
降低资源的消耗
提高响应速度
提高线程的可管理性
业务场景:
查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多时间
假如商品详细页的每个查询,需要如下标注的时间才能完成
那么,用户需要5.5s才能看到商品详细页的内容。很显然是不能接受的
如果多个线程同时完成这6步,也许就只需要1.5s就完成响应
Future是Java5添加的类,用来描述一个异步计算的结果,你可以使用’isDone‘方法检查计算是否完成,或者使用’get‘阻塞猪调用线程,直到计算完成返回结果,你也可以使用’cancel‘方法停止任务执行
虽然Future
以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不 方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的 初衷相违背,轮询的方式又会耗费无谓的 CPU 资源,而且也不能及时地得到计算结果,为 什么不能用观察者设计模式当计算结果完成及时通知监听者呢? 很多语言,比如 Node.js,采用回调的方式实现异步编程。Java 的一些框架,比如 Netty,自 己扩展了 Java 的 Future
接口,提供了addListener
等多个扩展方法;Google guava 也提供了 通用的扩展 Future;Scala 也提供了简单易用且功能强大的 Future/Promise 异步编程模式。 作为正统的 Java 类库,是不是应该做点什么,加强一下自身库的功能呢? 在 Java 8 中, 新增加了一个包含 50 个方法左右的类: CompletableFuture,提供了非常强大的 Future 的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以 通过回调的方式处理计算结果,并且提供了转换和组合 CompletableFuture 的方法。 CompletableFuture 类实现了 Future 接口,所以你还是可以像以前一样通过get
方法阻塞或 者轮询的方式获得结果,但是这种方式不推荐使用
CompletableFuture 和 FutureTask 同属于 Future 接口的实现类,都可以获取线程的执行结果。
CompletableFuture是jdk1.8以后添加的功能 CompletableFuture就类似于vue中promise的ajax请求,执行完了就.then
CompletableFuture提供了四个静态方法来创建一个异步操作
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main....start....");
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果: " + i);
}, executor);
System.out.println("main....end....");
executor是定义好的线程池,如果没有定义就用默认的
public static ExecutorService executor = Executors.newFixedThreadPool(10);
无返回值
main....start....
main....end....
当前线程: 12
运行结果: 5
CompletableFuture.supplyAsync(()->{
System.out.println("当前线程: "+Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果: "+i);
return i;
},executor);
executor是定义好的线程池,如果没有定义就用默认的
public static ExecutorService executor = Executors.newFixedThreadPool(10);
有返回值
main....start....
main....end....
当前线程: 12
运行结果: 5
System.out.println("main....start....");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果: " + i);
return i;
}, executor);
Integer integer = future.get();
System.out.println("main....end...."+integer);
}
executor是定义好的线程池,如果没有定义就用默认的
public static ExecutorService executor = Executors.newFixedThreadPool(10);
有返回值
main....start....
当前线程: 12
运行结果: 5
main....end....5
whenCompletable可以处理正常和异常的计算结果,exceptionally处理异常情况
whenCompletable和whenCompletableAsync的区别:
方法不以Asyc结尾,意味着Action使用相同的线程执行,而Asyc可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)
whenComplete没有异常
System.out.println("main....start....");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果: " + i);
return i;
}, executor).whenComplete((res,excption)->{
System.out.println("异步任务成功完成了。。。结果是:"+res+";异常是:"+excption);
});
// Integer integer = future.get();
System.out.println("main....end....");
main....start....
当前线程: 12
运行结果: 5
异步任务成功完成了。。。结果是:5;异常是:null
main....end....
whenComplete有异常
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;
}, executor).whenComplete((res,excption)->{
System.out.println("异步任务成功完成了。。。结果是:"+res+";异常是:"+excption);
});
// Integer integer = future.get();
System.out.println("main....end....");
main....start....
当前线程: 12
main....end....
异步任务成功完成了。。。结果是:null;异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
出现异常后还能进行处理exceptionally 异常处理逻辑
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;
}, executor).whenComplete((res,excption)->{
//虽然能得到异常信息,但是没法修改返回数据
System.out.println("异步任务成功完成了。。。结果是:"+res+";异常是:"+excption);
}).exceptionally(throwable -> {
//可以感知异常,同时返回默认值
return 10;
});
//R apply(T,t);
Integer integer = future.get();
System.out.println("main....end...."+integer);
}
main....start....
当前线程: 12
异步任务成功完成了。。。结果是:null;异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
main....end....10
和complete一样,可对结果做最后的处理(可处理异常),可改变返回值
有异常时
//方法执行完成后的处理,无论是成功完成还是失败完成
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果: " + i);
return i;
}, executor).handle((res,thr)->{
if (res!=null){
return res*2;
}
if (thr!=null){
return 0;
}
return 0;
});
// R apply(T t, U u);
Integer integer = future.get();
System.out.println("main....end...."+integer);
}
main....start....
当前线程: 12
main....end....0
因为有异常,handle就将返回值修改为0
无异常时
//方法执行完成后的处理,无论是成功完成还是失败完成
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 2
System.out.println("运行结果: " + i);
return i;
}, executor).handle((res,thr)->{
if (res!=null){
return res*2;
}
if (thr!=null){
return 0;
}
return 0;
});
// R apply(T t, U u);
Integer integer = future.get();
System.out.println("main....end...."+integer);
}
main....start....
当前线程: 12
运行结果: 5
main....end....10
异步返回结果为5,在handle中被修改了
thenApply方法:当一个线程依赖另一个线程时,获取上一个任务的返回的结果,并返回当前任务的返回值
/**
* 线程串行化
* 1)thenRun:不能获取到上一步的执行结果,无返回值
* .thenRunAsync(() -> {
* System.out.println("任务二启动了。。。。");
* }, executor);
*2)thenAcceptAsync:能接收上一步结果,但是无返回值
*.thenAcceptAsync(res->{
* System.out.println("任务二启动了"+res);
* },executor);
*3)thenApplyAsync:能接收上一步结果,有返回值
*/
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果: " + i);
return i;
}, executor).thenApplyAsync(res -> {
System.out.println("任务二启动了" + res);
return "Hello" + res;
}, executor);
//future.get()是一个阻塞方法
System.out.println("main....end...."+future.get());
}
main....start....
当前线程: 12
运行结果: 5
任务二启动了5
main....end....Hello5
thenAccept方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果
/**
* 线程串行化
* 1)thenRun:不能获取到上一步的执行结果,无返回值
* .thenRunAsync(() -> {
* System.out.println("任务二启动了。。。。");
* }, executor);
*2)thenAcceptAsync:能接收上一步结果,但是无返回值
*.thenAcceptAsync(res->{
System.out.println("任务二启动了"+res);
},executor);
*/
CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果: " + i);
return i;
}, executor).thenAcceptAsync(res->{
System.out.println("任务二启动了"+res);
},executor);
System.out.println("main....end....");
}
main....start....
当前线程: 12
运行结果: 5
main....end....
任务二启动了5
thenRun方法:只要上面的任务执行完成,就开始执行thenRun,只是处理完任务后,执行thenRun的后续操作
/**
* 线程串行化
* 1)thenRun:不能获取到上一步的执行结果
* .thenRunAsync(() -> {
System.out.println("任务二启动了。。。。");
}, executor);
*/
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果: " + i);
return i;
}, executor).thenRunAsync(() -> {
System.out.println("任务二启动了。。。。");
}, executor);
System.out.println("main....end....");
}
main....start....
当前线程: 12
运行结果: 5
main....end....
任务二启动了。。。。
带有Async默认是异步执行的,同之前。
以上都要前置任务成功完成
两个任务必须都完成,触发该任务
thenCombine:组合两个future,获取两个future的返回结果,并返回当前任务的返回值
/**
* 两个都完成
*/
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("任务一结束: ");
return i;
}, executor);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
System.out.println("任务二结束: ");
return "hello";
}, executor);
// R apply(T t, U u);
CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
return f1 + ":" + f2 + "->giao";
}, executor);
System.out.println("main....end...."+future.get());
}
main....start....
任务一线程启动了: 12
任务一结束:
任务二线程启动了: 13
任务二结束:
main....end....5:hello->giao
thenAcceptBoth:组合两个future,获取两个future的返回结果,然后处理任务,没有返回值
/**
* 两个都完成
*/
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("任务一结束: ");
return i;
}, executor);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
System.out.println("任务二结束: ");
return "hello";
}, executor);
// void accept(T t, U u);
future01.thenAcceptBothAsync(future02,(f1,f2)->{
System.out.println("任务3开始。。。之前的结果:"+f1+".....>"+f2);
},executor);
System.out.println("main....end....");
}
main....start....
任务一线程启动了: 12
任务一结束:
任务二线程启动了: 13
任务二结束:
main....end....
任务3开始。。。之前的结果:5.....>hello
runAfterBoth:组合两个future,不需要获取future的结果,只需要两个future处理完任务后,处理该任务
/**
* 两个都完成
*/
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("任务一结束: ");
return i;
}, executor);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
System.out.println("任务二结束: ");
return "hello";
}, executor);
future01.runAfterBothAsync(future02,()->{
System.out.println("任务三开始");
},executor);
System.out.println("main....end....");
}
main....start....
任务一线程启动了: 12
任务一结束:
任务二线程启动了: 13
任务二结束:
main....end....
任务三开始
当两个任务中,任意一个 future 任务完成的时候,执行任务。
applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。
/**
* 两个任务,只要有一个完成,我们就执行任务3
* runAfterEitherAsync:不感知结果,自己没有返回值
* acceptEitherAsync:感知结果,自己没有返回值
* applyToEitherAsync:自己感知结果,有返回值
*/
CompletableFuture<String> future = future01.applyToEitherAsync(future02, (res) -> {
System.out.println("任务3开始。。。之前的结果" + res);
return res.toString() + "->giao";
}, executor);
System.out.println("main....end...."+future.get());
}
main....start....
任务一线程启动了: 12
任务一结束:
任务二线程启动了: 13
任务3开始。。。之前的结果5
main....end....5->giao
任务二结束:
acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。
CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("任务一结束: ");
return i;
}, executor);
CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
try {
Thread.sleep(3000);
System.out.println("任务二结束: ");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello";
}, executor);
/**
* 两个任务,只要有一个完成,我们就执行任务3
* runAfterEitherAsync:不感知结果,自己没有返回值
* acceptEitherAsync:感知结果,自己没有返回值
*/
/* future01.runAfterEitherAsync(future02,()->{
System.out.println("任务3开始。。。之前的结果");
},executor);*/
future01.acceptEitherAsync(future02,(res)->{
System.out.println("任务3开始。。。之前的结果"+res);
},executor);
System.out.println("main....end....");
}
main....start....
任务一线程启动了: 12
任务一结束:
任务二线程启动了: 13
main....end....
任务3开始。。。之前的结果
任务二结束:
runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返 回值
/**
* 两个任务,只要有一个完成,我们就执行任务3
*/
future01.runAfterEitherAsync(future02,()->{
System.out.println("任务3开始。。。之前的结果");
},executor);
System.out.println("main....end....");
}
CompletableFuture future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("任务一结束: ");
return i;
}, executor);
CompletableFuture future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
System.out.println("任务二结束: ");
return "hello";
}, executor);
main....start....
任务一线程启动了: 12
任务一结束:
任务二线程启动了: 13
任务二结束:
main....end....
任务3开始。。。之前的结果
这个操作两个线程都完成了,无法查看runAfterEither的效果所以对代码future02作出修改
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("任务一结束: ");
return i;
}, executor);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
try {
Thread.sleep(3000);
System.out.println("任务二结束: ");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello";
}, executor);
/**
* 两个任务,只要有一个完成,我们就执行任务3
* runAfterEitherAsync:不感知结果,自己业务返回值
*/
future01.runAfterEitherAsync(future02,()->{
System.out.println("任务3开始。。。之前的结果");
},executor);
System.out.println("main....end....");
}
main....start....
任务一线程启动了: 12
任务一结束:
任务二线程启动了: 13
main....end....
任务3开始。。。之前的结果
任务二结束:
allOf:等待所有任务完成
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品图片信息");
return "hello.jpg";
});
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品de属性");
return "黑色+256G";
});
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品介绍");
return "华为";
});
// futureImg.get();
// futureAttr.get();
// futureDesc.get();
CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
allOf.get();//等待所有结果完成
// allOf.join();
main....start....
查询商品图片信息
查询商品de属性
查询商品介绍
main....end....
当一个线程执行比较慢时
CompletableFuture futureImg = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品图片信息");
return "hello.jpg";
});
CompletableFuture futureAttr = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品de属性");
return "黑色+256G";
});
CompletableFuture futureDesc = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("查询商品介绍");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "华为";
});
// futureImg.get();
// futureAttr.get();
// futureDesc.get();
CompletableFuture allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
// allOf.get();//等待所有结果完成
// allOf.join();
System.out.println("main....end....");
}
输出结果居然没有查询商品介绍 所有任务都没执行完就结束了
main....start....
查询商品图片信息
查询商品de属性
main....end....
改为线程池 无线存活阻塞
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品图片信息");
return "hello.jpg";
},executor);
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品de属性");
return "黑色+256G";
},executor);
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("查询商品介绍");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "华为";
},executor);
// futureImg.get();
// futureAttr.get();
// futureDesc.get();
CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
// allOf.get();//等待所有结果完成
// allOf.join();
System.out.println("main....end....");
}
main....start....
查询商品图片信息
查询商品de属性
main....end....
查询商品介绍
所以还不如直接
CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
allOf.get();//等待所有结果完成
想要获取到future中的内容
System.out.println("main....end...."+futureImg.get()+"=>"+futureAttr.get()+"=>"+futureDesc.get());
main....start....
查询商品图片信息
查询商品de属性
查询商品介绍
main....end....hello.jpg=>黑色+256G=>华为
anyOf:只要有一个任务完成
CompletableFuture
main....start....
查询商品图片信息
查询商品de属性
main....end....hello.jpg
查询商品介绍
} catch (InterruptedException e) {
e.printStackTrace();
}
return "华为";
},executor);
// futureImg.get();
// futureAttr.get();
// futureDesc.get();
CompletableFuture allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
// allOf.get();//等待所有结果完成
// allOf.join();
System.out.println("main....end....");
}
```console
main....start....
查询商品图片信息
查询商品de属性
main....end....
查询商品介绍
所以还不如直接
CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
allOf.get();//等待所有结果完成
想要获取到future中的内容
System.out.println("main....end...."+futureImg.get()+"=>"+futureAttr.get()+"=>"+futureDesc.get());
main....start....
查询商品图片信息
查询商品de属性
查询商品介绍
main....end....hello.jpg=>黑色+256G=>华为
anyOf:只要有一个任务完成
CompletableFuture
main....start....
查询商品图片信息
查询商品de属性
main....end....hello.jpg
查询商品介绍