1、Future接口理论知识复习
一句话:
Future
接口可以为主线程开一个分支任务,专门为主线程处理耗时和费力的复杂业务
Future
接口(FutureTask
实现类)定义了操作异步任务执行一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取
消、判断任务执行是否完毕等。
比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后
主线程就去做其他事情了,忙其它事情或者先执行完,过了一会才去获取子任务的执行结果或变更的任务状态。
举例上课买水案例给大家说明补充。。 。 。 。 。
2、Future接口常用实现类FutureTask异步任务
2.1、Future接口能干什么
Future
是Java5
新加的一个接口,它提供了一种异步并行计算的功能。
如果主线程需要执行一个很耗时的计算任务,我们就可以通过future
把这个任务放到异步线程中执行。主线程继续处理其他任务或者先行
结束,再通过Future
获取计算结果。
代码说话:
Runnable
接口Callable
接口
Future
接口和FutureTask
实现类
目的:异步多线程任务执行且返回有结果,三个特点:多线程/有返回/异步任务
(班长为老师去买水作为新启动的异步多线程任务且买到水有结果返回)
2.2、本源的Future接口相关架构
FutureTask
多线程/有返回/异步任务
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(new MyThread());
Thread t1 = new Thread(futureTask, "t1");
t1.start();
System.out.println(futureTask.get());
}
}
class MyThread implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("---come in call()");
return "hello Callable";
}
}
2.3、Future编码实战和优缺点分析
优点
future
+线程池异步多线程任务配合,能显著提高程序的执行效率
public static void main(String[] args) throws ExecutionException, InterruptedException {
//3个任务,目前开启多个 异步 任务线程来处理,请问耗时多少
long startTime = System.currentTimeMillis();
ExecutorService threadPool = Executors.newFixedThreadPool(3);//线程池
FutureTask<String> futureTask1 = new FutureTask<String>(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "task1 over";
});
threadPool.submit(futureTask1);
FutureTask<String> futureTask2 = new FutureTask<String>(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "task2 over";
});
threadPool.submit(futureTask2);
System.out.println(futureTask1.get());
System.out.println(futureTask2.get());
long endTime = System.currentTimeMillis();
System.out.println("---costTime" + (endTime - startTime) + "毫秒"); //---costTime505毫秒
threadPool.shutdown();
}
缺点
get()
阻塞
public class FutureAPIDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
FutureTask<String> futureTask = new FutureTask<String>(() -> {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "task over";
});
Thread t1 = new Thread(futureTask, "t1");
t1.start();
System.out.println(Thread.currentThread().getName()+"\t ---忙其他任务");
System.out.println(futureTask.get(3,TimeUnit.SECONDS));//过时不候,TimeoutException
}
}
/**
* 1、get容易导致阻塞,一般建议放在程序后面,一旦调用不见不散,非要等到结果才会离开,不管你是否计算完成,容易程序阻塞
* 2、加入我不愿意等待很长时间,我希望过时不候,可以自动离开
*
*/
idDone()
轮询
轮询的方式会耗费无谓的CPU
资源,而且也不见得能及时地得到计算结果.
如果想要异步获取结果,通常都会以轮询的方式去获取结果
public class FutureAPIDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
FutureTask<String> futureTask = new FutureTask<String>(() -> {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "task over";
});
Thread t1 = new Thread(futureTask, "t1");
t1.start();
System.out.println(Thread.currentThread().getName() + "\t ---忙其他任务");
// System.out.println(futureTask.get());//过时不候,TimeoutException
while (true){
if(futureTask.isDone()){
System.out.println(futureTask.get());
break;
}else {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("正在处理中");
}
}
}
结论
Future
对于结果的获取不是很友好,只能通过阻塞或轮询的方式得到任务的结果。
2.4、想完成一些复杂的业务
对于简单的业务场景使用Future完全ok
回调通知
应对Future
的完成时间,完成了可以告诉我,也就是我们的回调通知
通过轮询的方式去判断任务是否完成这样非常占CPU
并且代码也不优雅
创建异步任务
Future
+线程池的配合
多个任务前后依赖可以组合处理(水煮鱼)
想将多个异步任务的计算结果组合起来,后一个异步任务的计算结果需要前一个异步任务的值
将两个或多个异步计算合成一个异步计算,这几个异步计算互相独立,同时后面这个又依赖前一个处理的结果。
对计算速度选最快
当Future
集合中某个任务最快结束时,返回结果,返回第一名处理结果。
。。。。。。。
使用Future
之前提供的那点API就囊中羞涩,处理起来不够优雅,
这时候还是让CompletableFuture*以
声明式的方式优雅的处理这些需求
从i
到i++
Future
能干的,CompletableFuture
都能干
3、CompletableFuture对Future的改进
3.1、为什么会出现
get()
方法在Future
计算完成之前会一直处在阻塞状态下,
isDone()
方法容易耗费CPU资源,
对于真正的异步处理我们希望是可以通过传入回调函数,在 Future
结束时自动调用该回调函数,这样,我们就不用等待结果。
阻塞的方式和异步编程的设计理念相违背,而轮询的方式会耗费无谓的CPU
资源。因此,
JDK8
设计出CompletableFuture
。
CompletableFuture
提供了一种观察者模式类似的机制,可以让任务执行完成后通知监听的一方。
3.2、CompletableFuture和CompletionStage源码分别介绍
3.2.1、类架构说明
3.2.2、接口CompletionStage
3.2.3、接口CompletionFuture
3.3、核心的四个静态方法,来创建一个异步任务
不建议new
一个
3.3.1、runAsync 无返回值
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void>runAsync(Runnable runnable,Executor executor)
3.3.2、supplyAsync 有返回值
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplierExecutor executor)
3.3.4、上述Executor executor参数说明
没有指定Executor
的方法,直接使用默认的ForkJoinPool.commonPool()
作为它的线程池执行异步代码。
如果指定线程池,则使用我们自定义的或者特别指定的线程池执行异步代码
3.3.5、runAsync
public class CompletableFutureBuildDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
System.out.println(Thread.currentThread().getName());//ForkJoinPool.commonPool-worker-19
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(completableFuture.get()); //null
}
}
指定线程池
public class CompletableFutureBuildDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
System.out.println(Thread.currentThread().getName());//pool-1-thread-1
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
},threadPool);
System.out.println(completableFuture.get()); //null
threadPool.shutdown();
}
}
3.3.6、supplyAsync
public class CompletableFutureBuildDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture<Object> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());//pool-1-thread-1
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello supplyAsync";
}, threadPool);
System.out.println(completableFuture.get());//hello supplyAsync
threadPool.shutdown();
}
}
3.3.4、通用演示,减少阻塞和轮询,回调方法(whenComplete)&exceptionally
从Java8
开始引入了CompletableFuture
,它是Future
的功能增强版,减少阻塞和轮询
可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法
public class CompletableFutureUseDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "---come in");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("----1秒钟出结果: " + result);
return result;
}).whenComplete((r,e)->{
if (e == null) {
System.out.println("---计算完成,更新系统UpdateValue:" + r);
}
}).exceptionally(e ->{
e.printStackTrace();
System.out.println("异常情况" + e.getCause() + "\t" +e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "线程忙其他任务");
}
}
发现没有回调函数,主线程已经结束了,这线程类似于守护线程
默认线程池执行完会被shutdown,类似于守护线程
主线程不要立刻结束
//主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:暂停3秒钟线程
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "---come in");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("----1秒钟出结果: " + result);
return result;
}).whenComplete((r,e)->{
if (e == null) {
System.out.println("---计算完成,更新系统UpdateValue:" + r);
}
}).exceptionally(e ->{
e.printStackTrace();
System.out.println("异常情况" + e.getCause() + "\t" +e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "线程忙其他任务");
//主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:暂停3秒钟线程
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
threadPool.shutdown();
}
}
解释下为什么默认线程池关闭,自定义线程池记得关闭
public class CompletableFutureUseDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
try {
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "---come in");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("----1秒钟出结果: " + result);
return result;
}, threadPool).whenComplete((r, e) -> {
if (e == null) {
System.out.println("---计算完成,更新系统UpdateValue:" + r);
}
}).exceptionally(e -> {
e.printStackTrace();
System.out.println("异常情况" + e.getCause() + "\t" + e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "线程忙其他任务");
} catch (Exception e) {
}
//主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:暂停3秒钟线程
/* try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
threadPool.shutdown();
}
模拟报错
不管是否发生异常都会执行whenComplete
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
try {
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "---come in");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("----1秒钟出结果: " + result);
if (result > 5){
int i = 10/0;
}
return result;
}, threadPool).whenComplete((r, e) -> {
/*
if (e == null) {
System.out.println("---计算完成,更新系统UpdateValue:" + r);
}
*/
System.out.println("---计算完成,更新系统UpdateValue:" + r); //若出异常r为null
}).exceptionally(e -> {
e.printStackTrace();
System.out.println("异常情况" + e.getCause() + "\t" + e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "线程忙其他任务");
} catch (Exception e) {
}
threadPool.shutdown();
}
直接走到 exceptionally
3.3.5、CompletableFuture的优点
异步任务结束时,会自动回调某个对象的方法;
主线程设置好回调后,不再关心导步任务的执行,异步任务之间可以顺序执行
异步任务出错时,会自动回调某个对象的方法;
4、案例精讲-从电商网站的比价需求说开去
4.1、函数式编程已经主流
4.1.1、面试题
4.2、Lambda表达式+Stream流式调用+Chain链式调用+Java8函数时编程
4.2.1、Runnable
4.2.2、Function
4.2.3、Consumer,BiConsumer
4.2.4、Supplier
4.2.5、小总结
4.2、先说说join和get对比
public class CompletableFutureMallDemo {
public static void main(String[] args) {
/*Student student = new Student();
student.setId(12).setStudentName("li4").setMajor("english");*/
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
return "hello 1234";
});
//System.out.println(completableFuture.get());
System.out.println(completableFuture.join());//hello 1234 ,不需要抛异常
}
}
@Data
@Accessors(chain = true)
class Student{
private Integer id;
private String studentName;
private String major;
}
4.3、大厂业务需求说明
切记,功能->性能
电商网站比价需求分析
4.4、一波流Java8函数时编程带走-比价案例实战Case
package org.example;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @PACKAGE_NAME: PACKAGE_NAME
* @NAME: ConpletableFutureMallDemo
* @USER: Mrs.Wang
* @DATE: 2022/9/11
* @TIME: 19:49
* @DAY_NAME_SHORT: 周日
* @DAY_NAME_FULL: 星期日
* @PROJECT_NAME: JUC
**/
public class CompletableFutureMallDemo {
private static List<NetMall> list = Arrays.asList(
new NetMall("jd"),
new NetMall("dangdang"),
new NetMall("taoBao")
);
/**
* step by step
* @param list
* @param productName
* @return
*/
public static List<String> getPrice(List<NetMall> list,String productName){
//《mysql》 in tabao price is 90.43
return list.stream().
map(netMall -> String.format(productName + "in %s price is %.2f"
, netMall.getNetMallName()
, netMall.calcPrice(productName)))
.collect(Collectors.toList());
}
public static List<String> getPriceByCompletableFuture(List<NetMall> list,String productName){
//《mysql》 in tabao price is 90.43
List<CompletableFuture<String>> collect = list.stream().
map(netMall ->
//异步,同时去查
CompletableFuture.supplyAsync(() -> String.format(productName + "in %s price is %.2f"
, netMall.getNetMallName()
, netMall.calcPrice(productName))
)
).collect(Collectors.toList());
return collect.stream().map(s->s.join()).collect(Collectors.toList());
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
List<String> mysql = getPrice(list, "mysql");
for (String s : mysql) {
System.out.println(s);
}
long endTime = System.currentTimeMillis();
System.out.println("----costTime:"+(endTime-startTime)+"毫秒");
System.out.println("===========================================");
long startTime2 = System.currentTimeMillis();
List<String> mysql2 = getPriceByCompletableFuture(list, "mysql");
for (String s : mysql2) {
System.out.println(s);
}
long endTime2 = System.currentTimeMillis();
System.out.println("----costTime:"+(endTime2-startTime2)+"毫秒");}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class NetMall{
private String netMallName;
public double calcPrice(String productName){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return ThreadLocalRandom.current().nextDouble()*2 + productName.charAt(0);
}
}
增加网站
private static List<NetMall> list = Arrays.asList(
new NetMall("jd"),
new NetMall("dangdang"),
new NetMall("taoBao"),
new NetMall("pdd"),
new NetMall("xy")
);
5、CompletableFuture常用方法
5.1、获得结果getNow和触发计算complete
获取结果
public T get()
public T get(long timeout, TimeUnit unit)
public T join()
/*
没有计算完成的情况下,给我一个替代结果
立即获取结果不阻塞,
计算完,返回计算完成后的结果,返回complete的结果
没算完,返回设定的valueIfAbsent值
*/
public T getNow(T valuelfAbsent)
demo
public class CompletableFutureAPIDemo {
public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
{
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "abc";
});
// System.out.println(completableFuture.get());
// System.out.println(completableFuture.get(2l,TimeUnit.SECONDS));
// System.out.println(completableFuture.join());
System.out.println(completableFuture.getNow("xxx"));
}
}
触发计算
//是否打断get方法立即返回括号值
当调用completableFuture.get()被阻塞的时候, complete方法就是结束阻塞并get()获取设置的complete里面的值.
public boolean complete(T value)
public class CompletableFutureAPIDemo {
public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
{
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "abc";
});
// System.out.println(completableFuture.get());
// System.out.println(completableFuture.get(2l,TimeUnit.SECONDS));
// System.out.println(completableFuture.join());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
// System.out.println(completableFuture.getNow("xxx"));
/**
* false abc 线程计算1秒,主线程2秒
* true completeValue 线程计算2秒,主线程1秒,到这步如果还没有计算完,打断方法立即返回括号值
*/
System.out.println(completableFuture.complete("completeValue") + "\t" + completableFuture.join());
}
}
5.2、对计算结果进行处理
5.2.1、thenApply
计算结果存在依赖关系,这两个线程串行化
public class CompletableFutureAPI2Demo {
public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
{
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("111");
return 1;
},threadPool);
completableFuture.thenApply(f -> {
// int i = 1/0;
System.out.println("222");
return f + 2;
}).thenApply(f -> {
System.out.println("333");
return f + 3;
}).whenComplete((v,e) ->{
if (e == null) {
System.out.println("----计算结果: "+v);
}
}).exceptionally(e->{
e.printStackTrace();
System.out.println(e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName()+"---主线程先去忙其他任务");
threadPool.shutdown();
}
}
异常相关
- 由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停
5.2.2、handle
计算结果存在依赖关系,这两个线程串行化
异常相关
public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
{
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("111");
return 1;
}, threadPool);
completableFuture.handle((f, e) -> {
int i = 1/0;
System.out.println("222");
return f + 2;
}).handle((f, e) -> {
System.out.println("333");
return f + 3;//第二步出异常,导致f == null
}).whenComplete((v, e) -> {
if (e == null) {
System.out.println("----计算结果: " + v);
}
}).exceptionally(e -> {
e.printStackTrace();
System.out.println(e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "---主线程先去忙其他任务");
threadPool.shutdown();
}
}
5.2.3、总结
5.3、对计算结果进行消费
接受任务的处理结果,并消费处理,无返回结果
.5.3.1、thenAccept
public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
{
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1;
}, threadPool);
completableFuture.thenApply(f -> {
return f + 2;
}).thenApply(f -> {
return f + 3;
}).thenAccept((r)->{
System.out.println(r);// 6
});
System.out.println(Thread.currentThread().getName() + "---主线程先去忙其他任务");
threadPool.shutdown();
}
}
5.3.1、对比补充
Code之任务之间的顺序执行
thenRun
thenRun(Runnable runnable)
任务A
执行完执行B
,并且B
不需要A
的结果。B
相当于新的线程
thenAccept
thenAccept(Consumer action)
任务A
执行完执行B
,B
需要A
的结果,但是任务B
无返回值
thenApply
thenApply(Function fn)
任务A执行完执行B
,B
需要A
的结果,同时任务B
有返回值
package org.example;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @PACKAGE_NAME: org.example
* @NAME: CompletableFutureAPIDemo
* @USER: Mrs.Wang
* @DATE: 2022/9/11
* @TIME: 20:46
* @DAY_NAME_SHORT: 周日
* @DAY_NAME_FULL: 星期日
* @PROJECT_NAME: JUC
**/
public class CompletableFutureAPI3Demo {
public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
{
System.out.println(CompletableFuture.supplyAsync(() -> "resultA")
.thenRun(() -> {
}).join()); // null
System.out.println(CompletableFuture.supplyAsync(() -> "resultA")
.thenAccept((r) -> System.out.println(r) /*resultA*/).join()); //null
System.out.println(CompletableFuture.supplyAsync(() -> "resultA")
.thenApply((r) -> r + " resultB").join()); //resultA resultB
}
}
5.4、CompleteFuture和线程池说明
5.4.1、以thenRun和thenRunAsync为例,有什么区别?
都是thenRun
public class CompletableFutureWithThreadPoolDemo {
public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
{
ExecutorService threadPool = Executors.newFixedThreadPool(5);
try {
CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1号任务" + "\t" + Thread.currentThread().getName());
return "abcd";
},threadPool).thenRun(() -> {
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("2号任务" + "\t" + Thread.currentThread().getName());
}).thenRun(() -> {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("3号任务" + "\t" + Thread.currentThread().getName());
}).thenRun(() -> {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("4号任务" + "\t" + Thread.currentThread().getName());
});
completableFuture.get(2l,TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
发现用的是同一个线程池
第一个线程后面变为thenRunAsync
package org.example;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @PACKAGE_NAME: org.example
* @NAME: CompletableFutureAPIDemo
* @USER: Mrs.Wang
* @DATE: 2022/9/11
* @TIME: 20:46
* @DAY_NAME_SHORT: 周日
* @DAY_NAME_FULL: 星期日
* @PROJECT_NAME: JUC
**/
public class CompletableFutureWithThreadPoolDemo {
public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
{
ExecutorService threadPool = Executors.newFixedThreadPool(5);
try {
CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1号任务" + "\t" + Thread.currentThread().getName());
return "abcd";
},threadPool).thenRunAsync(() -> { // 变为thenRunAsync
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("2号任务" + "\t" + Thread.currentThread().getName());
}).thenRun(() -> {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("3号任务" + "\t" + Thread.currentThread().getName());
}).thenRun(() -> {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("4号任务" + "\t" + Thread.currentThread().getName());
});
completableFuture.get(2l,TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
发现又回到了默认线程池
5.4.2、小总结
-
没有传入自定义线程池,都用默认线程池
ForkJoinPool
; -
传入了一个自定义线程池,
如果你执行第一个任务的时候,传入了一个自定义线程池:
调用thenRun
方法执行第二个任务时,则第二个任务和第一个任务是共用同一个线程池。
调用thenRunAsync
执行第二个任务时,则第一个任务使用的是你自己传入的线程池,第二个任务使用的是ForkJoin线程池
- 备注
有可能处理太快,系统优化切换原则,直接使用main线程处理
其它如: thenAccept和thenAcceptAsync
,thenApply和thenApplyAsync
等,它们之间的区别也是同理
public class CompletableFutureWithThreadPoolDemo {
public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
{
ExecutorService threadPool = Executors.newFixedThreadPool(5);
try {
CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("1号任务" + "\t" + Thread.currentThread().getName());
return "abcd";
},threadPool).thenRun(() -> {
System.out.println("2号任务" + "\t" + Thread.currentThread().getName());
}).thenRun(() -> {
System.out.println("3号任务" + "\t" + Thread.currentThread().getName());
}).thenRun(() -> {
System.out.println("4号任务" + "\t" + Thread.currentThread().getName());
});
completableFuture.get(2l,TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
5.4.3、源码分析
5.5、对计算速度进行选用
5.5.1、谁快用谁
5.5.2、applyToEither
public class CompletableFutureFastDemo {
public static void main(String[] args) {
CompletableFuture<String> playA = CompletableFuture.supplyAsync(() -> {
System.out.println("A come in");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "playA";
});
CompletableFuture<String> playB = CompletableFuture.supplyAsync(() -> {
System.out.println("B come in");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "playB";
});
CompletableFuture<String> result = playA.applyToEither(playB, f -> f + " is winner");
System.out.println(Thread.currentThread().getName() + "\t" + "------: " + result.join());
}
}
5.6、对计算结果进行合并
两个CompletionStage
任务都完成后,最终能把两个任务的结果一起交给thenCombine
来处理
先完成的先等着,等待其他分支任务
5.6.1、thenCombine
标准版
public class CompletableFutureCombineDemo {
public static void main(String[] args) {
CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "\t---启动");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 10;
});
CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "\t---启动");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 20;
});
CompletableFuture<Integer> result = completableFuture1.thenCombine(completableFuture2, (c1, c2) -> {
System.out.println("----开始两个结果合并");
return c1 + c2;
});
System.out.println(result.join());
}
}
表达式
public class CompletableFutureCombineDemo {
public static void main(String[] args) {
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "\t---启动");
return 10;
}).thenCombine(CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "\t---启动");
return 20;
}), (c1, c2) -> {
return c1 + c2;
}).thenCombine(CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "\t---启动");
return 30;
}), (c1, c2) -> {
return c1 + c2;
});
System.out.println(completableFuture.join());
}
}