理解同步与异步区别
同步:就是在发出一个功能调用时,在没有得到结果之前,将一直处于等待中 即阻塞状态。也就是必须一件一件事做,等前一件做完了才能做下一件事
异步:异步通常意味着非阻塞,可以使得我们的任务单独运行在与主线程分离的其他线程中,并且通过回调可以在主线程中得到异步任务的执行状态,是否完成,和是否异常等信息。
CompletableFuture 简介
Future 与 CompletableFuture
Future 的主要缺点如下:
CompletableFuture 有 2个 异步方法
runAsync
异步调用有返回值方法
supplyAsync
使用 CompletableFuture
/**
* 主线程里面创建一个 CompletableFuture,然后主线程调用 get 方法会阻塞,最后我们
在一个子线程中使其终止
* @param args
*/
public static void main(String[] args) throws Exception{
CompletableFuture<String> future = new CompletableFuture<>();
new Thread(() -> {
try{
System.out.println(Thread.currentThread().getName() + "子线程开始干活");
//子线程睡 5 秒
Thread.sleep(5000);
//在子线程中完成主线程
future.complete("success");
}catch (Exception e){
e.printStackTrace();
}
}, "A").start();
//主线程调用 get 方法阻塞
System.out.println("主线程调用 get 方法获取结果为: " + future.get());
System.out.println("主线程完成,阻塞结束!!!!!!");
}
public static void main(String[] args) throws Exception {
System.out.println("主线程开始");
//运行一个没有返回值的异步任务
CompletableFuture<Void> future = CompletableFuture.runAsync(() -
> {
try {
System.out.println("子线程启动干活");
Thread.sleep(5000);
System.out.println("子线程完成");
} catch (Exception e) {
e.printStackTrace();
}
});
//主线程阻塞
future.get();
System.out.println("主线程结束");
}
/**
* 有返回值的异步任务
* @param args
*/
public static void main(String[] args) throws Exception{
System.out.println("主线程开始");
//运行一个有返回值的异步任务
CompletableFuture<String> future =
CompletableFuture.supplyAsync(() -> {
try {
System.out.println("子线程开始任务");
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
return "子线程完成了!";
});
//主线程阻塞
String s = future.get();
System.out.println("主线程结束, 子线程的结果为:" + s);
}
线程依赖
private static Integer num = 10;
/**
* 先对一个数加 10,然后取平方
*
* @param args
*/
public static void main(String[] args) throws Exception {
System.out.println("主线程开始");
CompletableFuture<Integer> future =
CompletableFuture.supplyAsync(() -> {
try {
System.out.println("加 10 任务开始");
num += 10;
} catch (Exception e) {
e.printStackTrace();
}
return num;
}).thenApply(integer -> {
return num * num;
});
Integer integer = future.get();
System.out.println("主线程结束, 子线程的结果为:" + integer);
thenAccept 消费处理结果, 接收任务的处理结果,并消费处理,无返回结果。
private static Integer num = 10;
public static void main(String[] args) throws Exception {
System.out.println("主线程开始");
CompletableFuture.supplyAsync(() -> {
try {
System.out.println("加 10 任务开始");
num += 10;
} catch (Exception e) {
e.printStackTrace();
}
return num;
}).thenApply(integer -> {
return num * num;
}).thenAccept(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println("子线程全部处理完成,最后调用了 accept,结果为:" +
integer);
}
});
}
exceptionally 异常处理,出现异常时触发
private static Integer num = 10;
public static void main(String[] args) throws Exception {
System.out.println("主线程开始");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
int i = 1 / 0;
System.out.println("加 10 任务开始");
num += 10;
return num;
}).exceptionally(ex -> {
//异常内容输出
System.out.println(ex.getMessage());
return -1;
});
System.out.println(future.get());
}
private static Integer num = 10;
public static void main(String[] args) throws Exception {
System.out.println("主线程开始");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
// int i= 1/0;
System.out.println("加 10 任务开始");
num += 10;
return num;
}).handle((i, ex) -> {
System.out.println("进入 handle 方法");
if (ex != null) {
System.out.println("发生了异常,内容为:" + ex.getMessage());
return -1;
} else {
System.out.println("正常完成,内容为: " + i);
return i;
}
});
System.out.println(future.get());
}
private static Integer num = 10;
public static void main(String[] args) throws Exception {
System.out.println("主线程开始");
//第一步加 10
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("加 10 任务开始");
num += 10;
return num;
});
//合并
CompletableFuture<Integer> future1 = future.thenCompose(i ->
//再来一个 CompletableFuture
CompletableFuture.supplyAsync(() -> {
return i + 1;
}));
System.out.println(future.get());
System.out.println(future1.get());
}
thenCombine 合并两个没有依赖关系的 CompletableFutures 任务
private static Integer num = 10;
public static void main(String[] args) throws Exception {
System.out.println("主线程开始");
CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {
System.out.println("加 10 任务开始");
num += 10;
return num;
});
CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {
System.out.println("乘以 10 任务开始");
num = num * 10;
return num;
});
//合并两个结果
CompletableFuture<Object> future = job1.thenCombine(job2, new
BiFunction<Integer, Integer, List<Integer>>() {
@Override
public List<Integer> apply(Integer a, Integer b) {
List<Integer> list = new ArrayList<>();
list.add(a);
list.add(b);
return list;
}
});
System.out.println("合并结果为:" + future.get());
}
private static Integer num = 10;
/**
* 先对一个数加 10,然后取平方
* @param args
*/
public static void main(String[] args) throws Exception{
System.out.println("主线程开始");
List<CompletableFuture> list = new ArrayList<>();
CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {
System.out.println("加 10 任务开始");
num += 10;
return num;
});
list.add(job1);
CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {
System.out.println("乘以 10 任务开始");
num = num * 10;
return num;
});
list.add(job2);
CompletableFuture<Integer> job3 = CompletableFuture.supplyAsync(() -> {
System.out.println("减以 10 任务开始");
num = num - 10;
return num;
});
list.add(job3);
CompletableFuture<Integer> job4 = CompletableFuture.supplyAsync(() -> {
System.out.println("除以 10 任务开始");
num = num / 10;
return num;
});
list.add(job4);
//多任务合并
List<Integer> collect =
list.stream().map(CompletableFuture<Integer>::join).collect(Collectors.toList());
System.out.println(collect);
}
private static Integer num = 10;
/**
* 先对一个数加 10,然后取平方
* @param args
*/
public static void main(String[] args) throws Exception{
System.out.println("主线程开始");
List<CompletableFuture> list = new ArrayList<>();
CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {
System.out.println("加 10 任务开始");
num += 10;
return num;
});
list.add(job1);
CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {
System.out.println("乘以 10 任务开始");
num = num * 10;
return num;
});
list.add(job2);
CompletableFuture<Integer> job3 = CompletableFuture.supplyAsync(() -> {
System.out.println("减以 10 任务开始");
num = num - 10;
return num;
});
list.add(job3);
CompletableFuture<Integer> job4 = CompletableFuture.supplyAsync(() -> {
System.out.println("除以 10 任务开始");
num = num / 10;
return num;
});
list.add(job4);
CompletableFuture<Void> future = CompletableFuture.allOf(job1, job2, job3, job4).whenComplete((a, b) -> {
// b为异常对象
if (b != null) {
System.out.println("error stack trace->");
b.printStackTrace();
} else {
System.out.println("run succ,result->" + a);
}
});
System.out.println(future.get());
}
private static Integer num = 10;
/**
* 先对一个数加 10,然后取平方
*
* @param args
*/
public static void main(String[] args) throws Exception {
System.out.println("主线程开始");
CompletableFuture<Integer>[] futures = new CompletableFuture[4];
CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(5000);
System.out.println("加 10 任务开始");
num += 10;
return num;
} catch (Exception e) {
return 0;
}
});
futures[0] = job1;
CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
System.out.println("乘以 10 任务开始");
num = num * 10;
return num;
} catch (Exception e) {
return 1;
}
});
futures[1] = job2;
CompletableFuture<Integer> job3 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("减以 10 任务开始");
num = num - 10;
return num;
} catch (Exception e) {
return 2;
}
});
futures[2] = job3;
CompletableFuture<Integer> job4 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(4000);
System.out.println("除以 10 任务开始");
num = num / 10;
return num;
} catch (Exception e) {
return 3;
}
});
futures[3] = job4;
CompletableFuture future = CompletableFuture.anyOf(futures);
System.out.println(future.get());
}
①. 获得结果和触发计算(get、getNow、join、complete)
getNow ()方法 如果计算完成 返回计算完成后的结果 如果调用时没有完成 则返回一个指定的替代值
重点 join 与get 区别
join方法和get( )方法作用一样,不同的是,join方法不抛出异常
这些不予操作演示
②. 对计算结果进行处理(thenApply、handle) 将线程串行化
①. public <U> CompletableFuture<U> thenApply
计算结果存在依赖关系,这两个线程串行化
由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停
②. public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn):
有异常也可以往下一步走,根据带的异常参数可以进一步处理
③. whenComplete:是执行当前任务的线程执行继续执行whenComplete的任务
④. whenCompleteAsync:是执行把whenCompleteAsync这个任务继续提交给线程池来进行执行
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {e.printStackTrace();}
return 1;
}).thenApply(s->{
// 这个s 是指上一步的返回值
System.out.println("-----1");
//如果加上int error=1/0; 由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫
停
//int error=1/0;
return s+1;
}).thenApply(s->{
System.out.println("-----2");
return s+2;
}).whenComplete((v,e)->{
// v 是指 异步操作数据的返回值 e指上面操作是否出现异常
if(e==null){
System.out.println("result-----"+v);
}
}).exceptionally(e->{
e.printStackTrace();
return null;
});
System.out.println(Thread.currentThread().getName()+"\t"+"over....");
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {e.printStackTrace();}
handle()与thenApply 效果相同 但是 thenApply 出现异常,线程立即停止 而handle 不会出现线程停止问题 会继续执行代码,同时也可以处理异常 等同于 thenApply() 和 exceptionally()结合
// 创建异步执行任务:
CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(()->{
return 1;
}).thenApply((i)->{
int q = 1/0;
System.out.println("我被处以0了");
return i+2;
}).handle((i,e)->{
if (e == null){
return i +3;
}else {
e.printStackTrace();
System.out.println("处理0");
return 9;
}
});
try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) {e.printStackTrace();}
System.out.println(cf.get());
③. 对计算结果进行消费(thenRun、thenAccept、thenApply)
①. thenRun(Runnable runnable)
任务A执行完执行B,并且B不需要A的结果 相当于另起一个线程
②. CompletableFuture<Void> thenAccept(Consumer<? super T> action)
任务A执行完成执行B,B需要A的结果,但是任务B 无返回值
③. public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
任务A执行完成执行B,B需要A的结果,同时任务B 有返回值
这些不予操作演示
某些方法 后缀 有Async 和没有 Async 后缀的方法的区别
带了Async的方法表示的是:会重新在线程池中启动一个线程来执行任务 这个线程池指的是CompletableFuture 创建时的默认线程池 即 ForkJoinPool.commonPool
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)
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 CompletableFuture<Void> thenRun(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor)
④. 对计算速度进行选用(applyToEither、acceptEither、runAfterEither)
①. public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
这个方法表示的是,谁快就用谁的结果
applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值
acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值
runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返回值
applyToEither使用
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 -> {
return f + " is winer";
});
System.out.println(Thread.currentThread().getName()+"\t"+"-----: "+result.join());
---------------------------------------------------------------------------------------------------------------------------
System.out.println(CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {e.printStackTrace();}
return 1;
}).applyToEither(CompletableFuture.supplyAsync(() -> {
try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) {e.printStackTrace();}
return 2;
}), r -> {
return r;
}).join());
runAfterEither 使用
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1;
});
CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 2;
});
CompletableFuture<Void> voidCompletableFuture = integerCompletableFuture.runAfterEither(integerCompletableFuture2, () -> System.out.println(integerCompletableFuture2.join()));
System.out.println(voidCompletableFuture.join());
带了Async的方法表示的是:会重新在线程池中启动一个线程来执行任务 这个线程池指的是CompletableFuture 创建时的默认线程池 即 ForkJoinPool.commonPool
public <U> CompletableFuture<U> applyToEither(
CompletionStage<? extends T> other, Function<? super T, U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(
CompletionStage<? extends T> other, Function<? super T, U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(
CompletionStage<? extends T> other, Function<? super T, U> fn,
Executor executor)
public CompletableFuture<Void> acceptEither(
CompletionStage<? extends T> other, Consumer<? super T> action)
public CompletableFuture<Void> acceptEitherAsync(
CompletionStage<? extends T> other, Consumer<? super T> action)
public CompletableFuture<Void> acceptEitherAsync(
CompletionStage<? extends T> other, Consumer<? super T> action,
Executor executor)
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,Runnable action)
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action)
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
Runnable action,
Executor executor)
⑤. 对计算结果进行合并(thenCombine、thenAcceptBoth、runAfterBoth)
①. public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
两个CompletionStage任务都完成后,最终把两个任务的结果一起交给thenCombine来处理
先完成的先等着,等待其他分支任务
thenCombine 使用
有返回值
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1;
});
CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 2;
});
CompletableFuture<Integer> future = integerCompletableFuture.thenCombine(integerCompletableFuture2, (a, b) -> a + b);
System.out.println(future.join());
------------------------------------------------ 简化-------------------------------------
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() ->2).thenCombine(CompletableFuture.supplyAsync(() ->1),(a, b) ->a+b);
System.out.println(future.join());
thenAcceptBoth 使用 无返回值
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1;
});
CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 2;
});
CompletableFuture<Void> voidCompletableFuture1 = integerCompletableFuture.thenAcceptBoth(integerCompletableFuture2, (a, b) -> System.out.println(a + b));
------------------------------------------------------ 简化-----------------------------------------------------
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> 1).thenAcceptBoth(CompletableFuture.supplyAsync(() -> 2), (a, b) -> System.out.println(a + b));
System.out.println(voidCompletableFuture.join());
runAfterBoth 使用 无返回值
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1;
});
CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 2;
});
CompletableFuture<Void> voidCompletableFuture1 = integerCompletableFuture.runAfterBoth(integerCompletableFuture2, () -> System.out.println(integerCompletableFuture.join()+integerCompletableFuture2.join()));
----------------------------------------- 简化 ---------------------------------------------
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> 1).runAfterBoth(CompletableFuture.supplyAsync(() -> 2),()-> System.out.println()) ;
thenCompose 合并两个有依赖关系的 CompletableFutures 的执行结果
thenCompose方法会在某个任务执行完成后,将该任务的执行结果作为方法入参然后执行指定的方法,该方法会返回一个新的CompletableFuture实例,如果该CompletableFuture实例的result不为null,则返回一个基于该result的新的CompletableFuture实例;如果该CompletableFuture实例为null,则,然后执行这个新任务,测试用例如下:
CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 2;
});
CompletableFuture<Integer> future= integerCompletableFuture2.thenCompose(param->{
System.out.println(param);
return CompletableFuture.supplyAsync(()-> param+ 2);
});
System.out.println( future.join());
--------- 简化 -----------------------------------
CompletableFuture.supplyAsync(() ->2).thenCompose(param ->{
return CompletableFuture.supplyAsync(()-> param+ 2);
});
⑥. 多任务组合(allOf、anyOf)
①. allOf:等待所有任务完成
(public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs))
②. anyOf:只要有一个任务完成
(public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs))
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品的图片信息");
return "hello.jpg";
});
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品的属性");
return "黑色+256G";
});
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {e.printStackTrace();}
System.out.println("查询商品介绍");
return "华为";
});
//需要全部完成
// futureImg.get();
// futureAttr.get();
// futureDesc.get();
//CompletableFuture<Void> all = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
//all.get();
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
anyOf.get();
System.out.println(anyOf.get());
System.out.println("main over.....");
同步与异步参考博客
Java面试题之:同步与异步?进程与线程?并发与并行?_faramita_of_mine的博客-CSDN博客_同步异步面试题
CompletableFuture 用法参考博客
Juc09_CompletableFuture概述、创建方式、常用API、电商比价需求_所得皆惊喜的博客-CSDN博客_completablefuture.allof
Java8 CompletableFuture 用法全解_孙大圣666的博客-CSDN博客_completablefuture
CompletableFuture详解~allOf_gqltt的博客-CSDN博客_completablefuture.allof
Java8 CompletableFuture(7) CompletableFuture allOf 获取所有线程结果_亚 瑟的博客-CSDN博客_completablefuture.allof