线程异步中CompletableFuture各种处理方案实例
- 1.线程异步
- 1.1CompletableFuture
- 1.2 CompletableFuture的异步方法
1.线程异步
多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,例如:A线程要请求某个资源,但是此资源正在被B线程使用中,因为没有同步机制存在,A线程仍然请求的到,A线程无需等待
1.1CompletableFuture
CompletableFuture提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通过回调的方式处理计算结果,也提供了转换和组合 CompletableFuture 的方法
1.2 CompletableFuture的异步方法
1.2.1supplyAsync方法
线程执行后有返回值
1.2.1.1 supplyAsync代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> ucompletableFuture =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future开始......");
int i=10/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i);
System.out.println("子线程future结束......");
return i;
});
//调用异步编排future
Integer integer=ucompletableFuture.get();
System.out.println("异步编排的返回值为"+integer);
}
}
/** 返回结果
* 子线程future开始......
* 线程名称ForkJoinPool.commonPool-worker-1线程的值为5
* 子线程future结束......
* 异步编排的返回值为5
*/
1.2.2runAsync方法
线程执行之后无返回值
1.2.2.1 runAsync 代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//定义线程池子
ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
4,
1,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(2),
Executors.defaultThreadFactory(),
//既不抛出错误也继续执行
new ThreadPoolExecutor.CallerRunsPolicy());
CompletableFuture<Void> future=CompletableFuture.runAsync(()->{
System.out.println("子线程future开始......");
int i=10/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i);
System.out.println("子线程future结束......");
},threadPoolExecutor);
future.get();
}
}
/** 返回结果
* 子线程future开始......
* 线程名称pool-1-thread-1线程的值为5
* 子线程future结束......
*/
1.2.3thenRunAsync方法
两个线程,1个线程执行之后在执行第2个线程
1.2.3.1 thenRunAsync代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程main开始......");
//定义线程池子
ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
4,
1,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(2),
Executors.defaultThreadFactory(),
//既不抛出错误也继续执行
new ThreadPoolExecutor.CallerRunsPolicy());
CompletableFuture<Void> completableFuture =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future开始......");
int i=10/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i);
System.out.println("子线程future结束......");
return i;
},threadPoolExecutor).thenRunAsync(()->{
System.out.println("子线程thenrun执行......");
System.out.println("线程名称"+Thread.currentThread().getName());
System.out.println("子线程thenrun结束......");
},threadPoolExecutor);
//调用执行
completableFuture.get();
System.out.println("主线程main结束......");
}
}
/** 返回结果
*主线程main开始......
* 子线程future开始......
* 线程名称pool-1-thread-1线程的值为5
* 子线程future结束......
* 子线程thenrun执行......
* 线程名称pool-1-thread-2
* 子线程thenrun结束......
* 主线程main结束......
*/
1.2.4 supplyAsync方法
将上一个线程返回值返回给下一个线程
1.2.4.1 supplyAsync代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程main开始......");
CompletableFuture<Integer> completableFuture =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future开始......");
int i=10/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i);
System.out.println("子线程future结束......");
return i;
}).thenApply((i)->{
System.out.println("接受的返回值的结果为"+i);
int k=i*5;
System.out.println("相乘的结果为"+k);
return k;
});
//调用异步方法
Integer I=completableFuture.get();
System.out.println("返回的结果为"+I);
}
}
/** 返回结果
主线程main开始......
子线程future开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为5
子线程future结束......
接受的返回值的结果为5
相乘的结果为25
返回的结果为25
*/
1.2.5 thenAccept方法
接受上一个线程返回值
1.2.5.1 thenAccept代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程main开始......");
CompletableFuture<Void> thenAccept =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future开始......");
int i=10/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i);
System.out.println("子线程future结束......");
return i;
}).thenAccept((i)->{
System.out.println("接受的返回值的结果为"+i);
int k=i*5;
System.out.println("相乘的结果为"+k);
});
//调用异步方法
thenAccept.get();
System.out.println("主线程main结束......");
}
}
/** 返回结果
主线程main开始......
子线程future开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为5
子线程future结束......
接受的返回值的结果为5
相乘的结果为25
主线程main结束......
*/
1.2.6 thenCompose方法
有返回值,返回值为U,两个CompletionStage流水线操作,将上一个线程的返回值返回给第二个线程,继续传递
1.2.6.1 thenCompose代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程main开始......");
CompletableFuture<Integer> thenAccept =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future开始......");
int i=10/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i);
System.out.println("子线程future结束......");
return i;
}).thenCompose(new Function<Integer, CompletionStage<Integer>>() {
@Override
public CompletionStage<Integer> apply(Integer t) {
CompletableFuture<Integer> future =CompletableFuture.supplyAsync(()->{
System.out.println("子线程thenAccept开始......");
int k=t/5;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+k);
System.out.println("子线程thenAccept结束......");
return k;
});
return future;
}
});
//调用异步方法
thenAccept.get();
System.out.println("主线程main结束......");
}
}
/** 返回结果
主线程main开始......
子线程future开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为5
子线程future结束......
子线程thenAccept开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为1
子线程thenAccept结束......
主线程main结束......
*/
*/
1.2.7 thenCombine方法
两个线程结束之后取两个线程的返回值
1.2.7.1 thenCombine代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程main开始......");
CompletableFuture<Integer> f1 =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future1开始......");
int i1=10/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i1);
System.out.println("子线程future1结束......");
return i1;
});
CompletableFuture<Integer> f2 =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future2开始......");
int i2=20/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i2);
System.out.println("子线程future2结束......");
return i2;
});
//t为第一个线程的返回值,u为第二个方法的返回值
CompletableFuture<Integer> thenCombine = f1.thenCombine(f2, (t, u) -> {
System.out.println("第一个线程的执行返回的结果"+t);
System.out.println("第二个线程的执行返回的结果"+u);
return t+u;
});
//调用异步
Integer integer=thenCombine.get();
System.out.println("异步的调用方法为:"+integer);
System.out.println("主线程main结束......");
}
}
/** 返回结果
主线程main开始......
子线程future1开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为5
子线程future1结束......
子线程future2开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为10
子线程future2结束......
第一个线程的执行返回的结果5
第二个线程的执行返回的结果10
异步的调用方法为:15
主线程main结束......
*/
1.2.8 thenAcceptBoth方法
等两个线程结束之后接收两个线程的返回值,不做处理,无返回值
1.2.8.1 thenAcceptBoth代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程main开始......");
CompletableFuture<Integer> f1 =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future1开始......");
int i1=10/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i1);
System.out.println("子线程future1结束......");
return i1;
});
CompletableFuture<Integer> f2 =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future2开始......");
int i2=20/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i2);
System.out.println("子线程future2结束......");
return i2;
});
//t为第一个线程的返回值,u为第二个方法的返回值
CompletableFuture<Void> acceptBoth = f1.thenAcceptBoth(f2, (t, u) -> {
System.out.println("第一个线程的执行返回的结果" + t);
System.out.println("第二个线程的执行返回的结果" + u);
});
//调用异步
acceptBoth.get();
System.out.println("主线程main结束......");
}
}
/** 返回结果
主线程main开始......
子线程future1开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为5
子线程future1结束......
子线程future2开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为10
子线程future2结束......
第一个线程的执行返回的结果5
第二个线程的执行返回的结果10
主线程main结束......
*/
1.2.9 runAfterBoth方法
设置两个线程的执行顺序,1个线程结束之后另外一个线程才能够执行
1.2.9.1 runAfterBoth代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程main开始......");
CompletableFuture<Integer> f1 =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future1开始......");
int i1=10/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i1);
System.out.println("子线程future1结束......");
return i1;
});
CompletableFuture<Integer> f2 =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future2开始......");
int i2=20/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i2);
System.out.println("子线程future2结束......");
return i2;
});
//t为第一个线程的返回值,u为第二个方法的返回值
CompletableFuture<Void> runAfterBoth = f1.runAfterBoth(f2, () -> {
System.out.println("有一个任务在执行.......runAfterBoth在执行");
});
//调用异步
runAfterBoth.get();
System.out.println("主线程main结束......");
}
}
/** 返回结果
主线程main开始......
子线程future1开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为5
子线程future1结束......
子线程future2开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为10
子线程future2结束......
有一个任务在执行.......runAfterBoth在执行
主线程main结束......
*/
1.2.10 runAfterBoth方法
返回两个线程的其中一个的返回值
1.2.10.1 runAfterBoth代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程main开始......");
CompletableFuture<Integer> f1 =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future1开始......");
int i1=10/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i1);
System.out.println("子线程future1结束......");
return i1;
});
CompletableFuture<Integer> f2 =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future2开始......");
int i2=20/2 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i2);
System.out.println("子线程future2结束......");
return i2;
});
//t为第一个线程的返回值,u为第二个方法的返回值 OR
CompletableFuture<Integer> applyToEither = f1.applyToEither(f2,r -> {
System.out.println("applyToEither线程名称,参数为"+r);
return r;
});
//调用异步
applyToEither.get();
System.out.println("主线程main结束......");
}
}
/** 返回结果
主线程main开始......
子线程future1开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为5
子线程future1结束......
子线程future2开始......
线程名称ForkJoinPool.commonPool-worker-1线程的值为10
子线程future2结束......
applyToEither线程名称,参数为5
主线程main结束......
*/
1.2.11 exceptionally方法
线程执行过程中异常抛出处理
1.2.11.1 exceptionally代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程main开始......");
CompletableFuture<Integer> f1 =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future1开始......");
int i1=10/0 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i1);
System.out.println("子线程future1结束......");
return i1;
}).exceptionally((t)->{
System.out.println("业务执行失败:"+t.getMessage());
return null;
});
//调用异步
f1.get();
System.out.println("主线程main结束......");
}
}
/** 返回结果
主线程main开始......
子线程future1开始......
业务执行失败:java.lang.ArithmeticException: / by zero
主线程main结束......
*/
1.2.12 whenComplete方法
whenComplete:对线程抛出的返回值和异常进行处理,返回值为 T,异常为 U,源码如下:
public CompletableFuture<T> whenComplete(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(null, action);
1.2.12.1 whenComplete代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程main开始......");
CompletableFuture<Integer> f1 =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future1开始......");
int i1=10/0 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i1);
System.out.println("子线程future1结束......");
return i1;
}).whenComplete((t,u)->{
System.out.println("执行结果为"+t);
if (u!=null){
System.out.println("业务执行失败:"+u.getMessage());
}
});
//调用异步
Integer integer=f1.get();
System.out.println("最终执行结果为"+integer);
System.out.println("主线程main结束......");
}
}
/** 返回结果
主线程main开始......
子线程future1开始......
执行结果为null
业务执行失败:java.lang.ArithmeticException: / by zero
*/
1.1.13 handle方法
对线程抛出的返回值和异常进行处理,返回值为 T,异常为 U
1.1.13.1 handle代码示例
package com.kkb.ThreadBinfa;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Test001 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程main开始......");
CompletableFuture<Integer> f1 =CompletableFuture.supplyAsync(()->{
System.out.println("子线程future1开始......");
int i1=10/0 ;
System.out.println("线程名称"+Thread.currentThread().getName()+"线程的值为"+i1);
System.out.println("子线程future1结束......");
return i1;
}).handle((t,u)->{
int res=-1;
System.out.println("执行结果为"+t);
if (u!=null){
System.out.println("业务执行失败:"+u.getMessage());
}else{
res=t*5;
}
return res;
});
//调用异步
Integer integer=f1.get();
System.out.println("最终执行结果为"+integer);
System.out.println("主线程main结束......");
}
}
/** 返回结果
主线程main开始......
子线程future1开始......
执行结果为null
业务执行失败:java.lang.ArithmeticException: / by zero
最终执行结果为-1
主线程main结束......
*/