Future接口理论知识复习
Future接口(FutureTask实现类)定义了操作异步任务执行一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务执行是否完毕等。
比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后,主线程就去做其他事情了,忙其他事情或者先执行完,过了一会才去获取子任务的执行结果或变更的任务状态。
一句话:Future接口可以为主线程开一个分支任务,专门为主线程处理耗时和费力的复杂业务。
Future接口常用实现类FutureTask异步任务
Future接口能干什么?
Future是Java5新加的一个接口,它提供了一种异步并行计算的功能。如果主线程需要执行一个很耗时的计算任务,我们就可以通过Future把这个任务放到异步线程中执行。 主线程继续处理其他任务或者先行结束,再通过Future获取计算结果。
代码说话:
目的:异步多线程任务执行且返回有结果,三个特点:多线程/有返回/异步任务。
本源的Future接口相关的架构
package com.lzx.juc.cf;
import java.util.concurrent.*;
/**
* @author admin
*/
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask<>(new MyThread());
Thread t1 = new Thread(futureTask, "t1");
t1.start();
System.out.println(futureTask.get());
}
}
class MyThread implements Callable {
@Override
public String call() {
System.out.println("-----come in call() ");
return "hello Callable";
}
}
Future编码实战和有缺点分析
优点
Future+线程池异步多线程任务配合,能显著提高程序的执行效率。
上述案例case
package com.lzx.juc.cf;
import java.util.concurrent.*;
/**
* @author admin
*/
public class FutureThreadPoolDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//3个任务,目前开启多个异步任务线程来处理,请问耗时多少?
ExecutorService threadPool = Executors.newFixedThreadPool(3);
long startTime = System.currentTimeMillis();
FutureTask futureTask1 = new FutureTask<>(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "task1 over";
});
threadPool.submit(futureTask1);
FutureTask futureTask2 = new FutureTask<>(() -> {
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "task2 over";
});
threadPool.submit(futureTask2);
System.out.println(futureTask1.get());
System.out.println(futureTask2.get());
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("----costTime: " + (endTime - startTime) + " 毫秒");
System.out.println(Thread.currentThread().getName() + "\t -----end");
threadPool.shutdown();
}
private static void m1() {
//3个任务,目前只有一个线程main来处理,请问耗时多少?
long startTime = System.currentTimeMillis();
//暂停毫秒
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("----costTime: " + (endTime - startTime) + " 毫秒");
System.out.println(Thread.currentThread().getName() + "\t -----end");
}
}
缺点
Code1
package com.bilibili.juc.cf;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* 1 get容易导致阻塞,一般建议放在程序后面,一旦调用不见不散,非要等到结果才会离开,不管你是否计算完成,容易程序堵塞。
* 2 假如我不愿意等待很长时间,我希望过时不候,可以自动离开.
*
* @author admin
*/
public class FutureAPIDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
FutureTask futureTask = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + "\t -----come in");
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());
System.out.println(futureTask.get(3,TimeUnit.SECONDS));
}
}
get()阻塞
一旦调用get()方法求结果,如果计算没有完成容易导致程序阻塞。
Code2
package com.lzx.juc.cf;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* 1 get容易导致阻塞,一般建议放在程序后面,一旦调用不见不散,非要等到结果才会离开,不管你是否计算完成,容易程序堵塞。
* 2 假如我不愿意等待很长时间,我希望过时不候,可以自动离开.
*
* @author admin
*/
public class FutureAPIDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
FutureTask futureTask = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + "\t -----come in");
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());
//System.out.println(futureTask.get(3,TimeUnit.SECONDS));
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("正在处理中,不要再催了,越催越慢 ,再催熄火");
}
}
}
}
idDone()轮询
轮询的方式会消耗无谓的CPU资源,而且也不见得能及时的得到计算结果;如果想要异步获取结果,通常都会以轮询的方式去获取结果,尽量不要阻塞。
结论
Future对于结果的获取不是很友好,只能通过阻塞或轮询的方式得到任务的结果。
想完成一些复杂的任务
对于简单的业务场景使用Future是完全的OK的。
Future就显得有些力不从心了;
回调通知
应对Future的完成时间,完成了可以告诉我,也就是我们的回调通知;通过轮询的方式去判断任务是否完成这样非常占CPU,并且代码也不优雅。
创建异步任务
Future+线程池配合
多个任务前后依赖可以组合处理
1、想将多个异步任务的计算结果组合起来,后一个异步任务的计算结果需要前一个异步任务的值。将两个或多个异步计算合成一个异步计算,这几个异步计算互相独立,同时后面这个有依赖前一个处理的结果。
2、对计算速度选最快;当Future集合中某个任务最快结束时,返回结果,返回第一名处理结果。
。。。。。。
再这样的场景下,再使用Future之前提供的那点API就囊中羞涩,处理起来不够优雅,这时候还是让CompletableFuture以声明式的方式优雅的处理这些需求。
从i到i++
Future能干的,CompletableFutrue都能干。
CompletableFuture对Future的改进
CompletableFuture为什么会出现?
get()方法在Future计算完成之前会一直在阻塞状态下,isDone()方法容易消耗CPU资源,对于真正的异步处理我们希望是可以通过传入回调函数,在Future结束时自动调用该回调函数,这样,我们就不用等待结果。
阻塞的方式和异步编程的设计理念相违背,而轮询的方式会消耗无谓的CPU资源。因此,JDK8设计出CompletableFuture。
CompletableFuture提供了一种观察者模式类似的机制,可以让任务执行完成后通知监听的一方。
CompletableFuture和CompletionStage源码分别介绍
类架构说明
接口CompletionStage
是什么?
代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段,有些类似Linux系统的管道分隔符传参数。
类CompletableFuture
是什么?
核心的四个静态方法,来创建一个异步任务
runAsync无返回值
public static CompletableFutrue runAsync(Runnable runnable);
public static CompletableFuture runAsync(Runnable runnable, Executor executor);
supplyAsync有返回值
public static CompletableFuture supplyAsync(Supplier supplier);
public static CompletableFuture supplyAsync(Supplier supplier, Executor executor );
上述Executor executor参数说明
没有指定Executor的方法,直接使用默认的ForkJoinPool.commonPool()作为它的线程池执行异步代码。如果指定线程池,则使用我们自定义的或者特别指定的线程池执行异步代码。
无返回值
package com.lzx.juc.cf;
import java.util.concurrent.*;
/**
* @author admin
*/
public class CompletableFutureBuildDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture completableFuture = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName());
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, threadPool);
System.out.println(completableFuture.get());
threadPool.shutdown();
}
}
有返回值
package com.lzx.juc.cf;
import java.util.concurrent.*;
/**
* @author admin
*/
public class CompletableFutureBuildDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello supplyAsync";
}, threadPool);
System.out.println(completableFuture.get());
threadPool.shutdown();
}
}
Code之通用演示,减少阻塞和轮询
从Java8开始引入了CompletableFuture,它是Future的功能增强版,减少阻塞和轮询,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法。
package com.lzx.juc.cf;
import java.util.concurrent.*;
/**
* @author admin
*/
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);
if (result > 2) {
int i = 10 / 0;
}
return result;
}, threadPool).whenComplete((v, e) -> {
if (e == null) {
System.out.println("-----计算完成,更新系统UpdateValue:" + v);
}
}).exceptionally(e -> {
e.printStackTrace();
System.out.println("异常情况:" + e.getCause() + "\t" + e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "线程先去忙其它任务");
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
//主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:暂停3秒钟线程
//try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
}
private static void future1() throws InterruptedException, ExecutionException {
CompletableFuture completableFuture = 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;
});
System.out.println(Thread.currentThread().getName() + "线程先去忙其它任务");
System.out.println(completableFuture.get());
}
}
解释下为什么默认的线程池关闭,自定义的线程池记得关闭。
CompletableFuture的优点
异步任务结束时,会自动回调某个对象方法;
主线程设置好回调后,不再关心异步任务的执行,异步任务之间可以顺序执行;
异步任务出错时,会自动回调某个对象的方法;
案例精讲-从电商网站的比价需求说开去
先看看大厂面试题
函数式编程已经主流
Lambda表达式+Stream流失调用+Chain链式调用+Java8函数式编程。
Runnable
Runnable已经说过很多次了,无参数,无返回值。
Function
Function
Consumer
Consumer消费型函数接口,接受一个参数,没有返回值。
BiConsumer
BiConsumer
Supplier
Supplier供给型函数接口,没有参数,有一个返回值。
小总结
先说说join和get对比
join与get在功能上几乎没有什么区别,区别在云get在编译期会有抛出检查异常,而join不会。
说说你过去工作中的项目亮点?大厂业务需求说明?
切记,功能->性能,先满足功能的完成,再到性能的完善。
电商网站比价需求分析。
1、 需求说明
1.1、 同一款产品,同时搜索出同款产品在各大电商平台的售价;
1.2、 同一款产品,同时搜索出本产品在同一个电商平台下,各个入驻卖家售价是多少?
2、输出返回:
出来结果希望是同款产品的在不同地方的价格清单列表,返回一个List
《mysql》in jd price is 88.5
《mysql》 in dangdang price is 86.11
《mysql》 in Taobao price is 90.43
3、解决方案,比对同一个商品在各个平台上的价格,要求获得一个清单列表
1、step by step,按部就班,查完京东查淘宝,查完淘宝查天猫……
2、all in,万箭齐发,一口气对线程异步任务同时查询。
一波流Java8函数式编程带走-比价案例实战Case
package com.lzx.juc.cf;
import lombok.*;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @author admin
*
* 案例说明:电商比价需求,模拟如下情况:
*
* 1需求:
* 1.1 同一款产品,同时搜索出同款产品在各大电商平台的售价;
* 1.2 同一款产品,同时搜索出本产品在同一个电商平台下,各个入驻卖家售价是多少
*
* 2输出:出来结果希望是同款产品的在不同地方的价格清单列表,返回一个List
* 《mysql》 in jd price is 88.05
* 《mysql》 in dangdang price is 86.11
* 《mysql》 in taobao price is 90.43
*
* 3 技术要求
* 3.1 函数式编程
* 3.2 链式编程
* 3.3 Stream流式计算
*/
public class CompletableFutureMallDemo {
static List list = Arrays.asList(
new NetMall("jd"),
new NetMall("dangdang"),
new NetMall("taobao"),
new NetMall("pdd"),
new NetMall("tmall")
);
/**
* step by step 一家家搜查
* List ----->map------> List
*
*/
public static List getPrice(List list, String productName) {
//《mysql》 in taobao 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());
}
/**
* List ----->List>------> List
*
*/
public static List getPriceByCompletableFuture(List list, String productName) {
return list.stream().map(netMall ->
CompletableFuture.supplyAsync(() -> String.format(productName + " in %s price is %.2f",
netMall.getNetMallName(),
netMall.calcPrice(productName))))
.collect(Collectors.toList())
.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
List list1 = getPrice(list, "mysql");
for (String element : list1) {
System.out.println(element);
}
long endTime = System.currentTimeMillis();
System.out.println("----costTime: " + (endTime - startTime) + " 毫秒");
System.out.println("--------------------");
long startTime2 = System.currentTimeMillis();
List list2 = getPriceByCompletableFuture(list, "mysql");
for (String element : list2) {
System.out.println(element);
}
long endTime2 = System.currentTimeMillis();
System.out.println("----costTime: " + (endTime2 - startTime2) + " 毫秒");
}
}
class NetMall {
@Getter
private String netMallName;
public NetMall(String netMallName) {
this.netMallName = netMallName;
}
public double calcPrice(String productName) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return ThreadLocalRandom.current().nextDouble() * 2 + productName.charAt(0);
}
}
CompletableFuture常用方法
1、获得结果和触发计算
获取结果
public T get();---不见不散
public T get(long timeout, TimeUnit unit);---过时不候
public T join();
public T getNow(T valueIfAbsent);----没有计算完成的情况下,给一个替代的结果;立即获取结果不阻塞(计算完,返回计算完成后的结果;没计算完,返回设定的valueIfAbsent值)。
public boolean complete(T value);----主动触发计算;是否打断get方法立即反回括号值。
package com.lzx.juc.cf;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
* @author admin
*/
public class CompletableFutureAPIDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
group1();
}
/**
* 获得结果和触发计算
*
*/
private static void group1() throws InterruptedException, ExecutionException {
CompletableFuture 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"));
System.out.println(completableFuture.complete("completeValue") + "\t" + completableFuture.get());
}
}
2、对计算结果进行处理
thenApply()----计算结果存在依赖关系,这两个线程串行化。
package com.lzx.juc.cf;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @author admin
*/
public class CompletableFutureAPI2Demo {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("111");
return 1;
}, threadPool).thenApply(f -> {
int i=10/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();
}
}
异常相关;由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停。
handle()----计算结果存在依赖关系,这两个线程串行化。
package com.bilibili.juc.cf;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @author admin
*/
public class CompletableFutureAPI2Demo {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("111");
return 1;
}, threadPool).handle((f, e) -> {
int i = 10 / 0;
System.out.println("222");
return f + 2;
}).handle((f, e) -> {
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();
}
}
异常相关;有异常也可以往下一步走,根据带的异常参数可以进一步处理。
总结
3、对计算结果进行消费
接收任务的处理结果,并消费处理,无返回结果。
thenAccept();
package com.lzx.juc.cf;
import java.util.concurrent.CompletableFuture;
/**
* @author admin
*/
public class CompletableFutureAPI3Demo {
public static void main(String[] args) {
CompletableFuture.supplyAsync(() -> 1)
.thenApply(f -> f + 2)
.thenApply(f -> f + 3)
.thenAccept(System.out::println);
}
}
对比补充
Code之任务之间的顺序执行
thenRun()
thenRun(Runnable runnable);---任务A执行完成执行B,并且B不需要A的结果。
thenAccept()
thenAccpet(Consumer action);---任务A执行完执行B,B需要A的结果,但是任务B无返回值。
thenApply()
thenApply(Function fn);---任务A执行完执行B,B需要A的结果,同时任务B有返回值。
code
package com.lzx.juc.cf;
import java.util.concurrent.CompletableFuture;
/**
* @author admin
*/
public class CompletableFutureAPI3Demo {
public static void main(String[] args) {
System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {}).join());
System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenAccept(System.out::println).join());
System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenApply(r -> r + "resultB").join());
}
}
CompletableFuture和线程池说明
以thenRun和thenRunAsync为例,有什么区别?
package com.lzx.juc.cf;
import java.util.concurrent.*;
/**
* @author admin
*/
public class CompletableFutureWithThreadPoolDemo {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(5);
try {
CompletableFuture 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(() -> {
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());
});
System.out.println(completableFuture.get(2L, TimeUnit.SECONDS));
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
小总结
1、没有传入自定义线程池,都用默认线程池ForkJoinPool。
2、传入了一个自定义线程池,如果你执行第一个任务的时候,传入了一个自定义线程池:
调用thenRun方法执行第二个任务时,则第二个任务和第一个任务是共用同一个线程池。
调用thenRunAsync执行第二个任务时,则第一个任务使用的是你自己传入的线程池,第二个任务使用的是ForkJoinPoo线程池。
3、备注
有可能处理太快,系统优化切换原则,直接使用main线程处理。
其他如:thenAccept和thenAcceptAsync,thenApply和thenApplyAsync等,它们之间的区别也是同理。
调用thenRunAsync执行第二个任务时,则第一个任务使用的是你自己传入的线程池,第二个任务使用的是ForkJoinPoo线程池。
源码分析
4、对计算速度进行选用
谁快用谁
applyToEither()
package com.lzx.juc.cf;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* @author admin
*/
public class CompletableFutureFastDemo {
public static void main(String[] args) {
CompletableFuture playA = CompletableFuture.supplyAsync(() -> {
System.out.println("A come in");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "playA";
});
CompletableFuture playB = CompletableFuture.supplyAsync(() -> {
System.out.println("B come in");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "playB";
});
CompletableFuture result = playA.applyToEither(playB, f -> f + " is winer");
System.out.println(Thread.currentThread().getName() + "\t" + "-----: " + result.join());
}
}
5、对计算结果进行合并
两个CompletableStage任务都完成后,最终能把两个任务的结果一起交给thenCombine来处理;先完成的先等着,等待其他分支任务。
thenCombine()
Code标准版,好理解先拆分
package com.lzx.juc.cf;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* @author admin
*/
public class CompletableFutureCombineDemo {
public static void main(String[] args) {
CompletableFuture completableFuture1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "\t ---启动");
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 10;
});
CompletableFuture completableFuture2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "\t ---启动");
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 20;
});
CompletableFuture result = completableFuture1.thenCombine(completableFuture2, (x, y) -> {
System.out.println("-----开始两个结果合并");
return x + y;
});
System.out.println(result.join());
}
}
Code表达式