CompletableFuture提供了一种观察者模式类似机制,可以让任务执行完成后通知监听的一方。
1 Future
Future提供异步并行计算功能,如果主线程需要一个很耗时的计算任务,我们可以通过Future把这个任务放在异步线程去执行,
主线程则去执行其他任务,处理完后,再用Future获取结果。
但是Future对于结果的获取并不是很友好,只能通过阻塞或轮询的方式得到任务的结果,Future.get()就是阻塞调用,
在线程获取结果之前get方法会一直阻塞,Future提供了isDone方法,可以在程序中使用这个方法查询执行结果
Demo:
Future操作
/**
* Future
* Future
* Future
* Future
*
* Result:
* calFuncTask: 4673466.899862001
* calFuncTask1: 32022.75379807269
* TimeCost: 822
*
* Future
* Future.get()get
* FutureisDone
*/
@Test
public void futureTest() throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
//
long startTime = System.currentTimeMillis();
//
FutureTask<Double> calFuncTask = new FutureTask<>(() -> {
Thread.sleep(300);
return 19*28.3*65.4*132.8989;
});
executorService.submit(calFuncTask);
//
Thread.sleep(300);
//
FutureTask<Double> calFuncTask1 = new FutureTask<>(() -> {
Thread.sleep(500);
return 19.313*2.3*5.4245*132.8989;
});
executorService.submit(calFuncTask1);
// isDone
boolean done = false;
while(!done){
done = calFuncTask1.isDone();
Thread.sleep(50);
System.out.println("calFuncTask1: " + done);
}
System.out.println("calFuncTask: " + calFuncTask.get() + "\n" + "calFuncTask1: " + calFuncTask1.get() +
"\n" + "TimeCost: " + (System.currentTimeMillis() - startTime));
}
2 CompletableFuture
CompletableFuture提供了一种观察者模式类似机制,可以让任务执行完成后通知监听的一方。
Completable 三个使用场景:
1 创建异步任务
2 简单任务异步回调
3 多任务组合处理
supplyAsync执行CompletableFuture任务,支持返回值。
runAsync执行CompletableFuture任务,没有返回值。
Demo:
CompletableFuture操作
/**
* CompletableFuture
* CompletableFuture
*
* Result:
* calFuncTask: 4673466.899862001
* calFuncTask1: 32022.75379807269
* TimeCost: 582
*
* Completable
*
*
*
* supplyAsyncCompletableFuture
* runAsyncCompletableFuture
*
*/
@Test
public void completableFutureTest() throws InterruptedException, ExecutionException, TimeoutException {
//
long startTime = System.currentTimeMillis();
//
CompletableFuture<Double> calFuncTask = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 19*28.3*65.4*132.8989;
});
//
CompletableFuture<Double> calFuncTask1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 19.313*2.3*5.4245*132.8989;
});
//
Thread.sleep(300);
//
boolean done = false;
while(!done){
done = calFuncTask1.isDone();
Thread.sleep(50);
System.out.println("calFuncTask1 Status: " + done);
}
Double result = calFuncTask.get(2, TimeUnit.SECONDS);
Double result1 = calFuncTask1.get();
System.out.println("calFuncTask: " + result + "\n" + "calFuncTask1: " + result1 + "\n" + "TimeCost: " +
(System.currentTimeMillis() - startTime));
}
3 CompletableFuture 任务异步回调
3.1 thenRun / thenRunAsync
public CompletableFuture thenRun(Runnable action);
public CompletableFuture thenRunAsync(Runnable action);
CompletableFuture的thenRun方法,就是做完第一个任务后,再做第二个任务,某个任务执行完成后,执行回调方法,但是前后两个任务没有参数的传递,
第二个任务也没有返回值。
thenRun 和 thenRunSync 的区别
如果执行第一个任务的时候,传入了一个自定义的线程池:
调用thenRun方法执行第二个任务时,第二个任务和第一个任务使用的同一线程池
调用thenRunAsync方法执行第二个任务时,第一个任务使用自定义,而第二个使用ForkJoinPool
后续的区别和这个一样
Demo:
thenRun / thenRunAsync
/**
* CompletableFuture
* 1. thenRun/thenRunSync
* CompletableFuturethenRun
*
*
* Result:
* orgFuture called
* Then we go thenRunFuture
* null
*
* thenRun thenRunSync
* :
* thenRun
* thenRunAsyncForkJoinPool
*/
@Test
public void thenRunTest() throws ExecutionException, InterruptedException {
// Future
CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("orgFuture called");
return "orgFuture result";
});
// Future
CompletableFuture<Void> thenRunFuture = orgFuture.thenRun(() -> {
System.out.println("Then we go thenRunFuture");
});
System.out.println(thenRunFuture.get());
}
3.2 thenAccept / thenAcceptAsync
CompletableFuture的thenAccept方法表示,第一个任务执行完成后,执行第二个回调方法任务,
会将该任务的执行结果,作为入参,传递到回调方法中,但是回调方法是没有返回值的。
Demo:
thenAccept / thenAcceptAsync
/**
* 2. thenAccept/thenAcceptAsync
* CompletableFuturethenAccept
*
*
* Result:
* orgFuture called
* thenAcceptFuture validation successfully
* thenAcceptFuture end
* null
*/
@Test
public void thenAcceptTest() throws ExecutionException, InterruptedException {
//
CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("orgFuture called");
return "the result of orgFuture";
});
//
CompletableFuture<Void> thenAcceptFuture = orgFuture.thenAccept((result) -> {
if (result.equals("the result of orgFuture")){
System.out.println("thenAcceptFuture validation successfully");
}
System.out.println("thenAcceptFuture end");
});
System.out.println(thenAcceptFuture.get());
}
3.3 thenApply / thenApplyAsync
CompletableFuture的thenApply方法表示,第一个任务执行完成后,执行第二个回调方法任务,
会将该任务的执行结果,作为入参,传递到回调方法中,并且回调方法是有返回值的。
Demo:
thenApply / thenApplyAsync
/**
* 3. thenApply/thenApplyAsync
* CompletableFuturethenApply
*
*
* Result:
* orgFuture called
* thenApplyFuture Validation Success
*/
@Test
public void thenApplyTest() throws ExecutionException, InterruptedException {
//
CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("orgFuture called");
return "the result of orgFuture";
});
//
CompletableFuture<String> thenApplyFuture = orgFuture.thenApply((result) -> {
if (result.equals("the result of orgFuture")){
return "thenApplyFuture Validation Success";
}
return "thenApplyFuture Validation Failed";
});
System.out.println(thenApplyFuture.get());
}
3.4 exceptionally
CompletableFuture的exceptionally方法表示,某个任务执行异常时,执行的回调方法;并且用抛出异常作为参数,传递到回调方法.
Demo:
exceptionally
/**
* 4. exceptionally
* CompletableFutureexceptionally
*
*
* Result:
* Current thread name: ForkJoinPool.commonPool-worker-19
* java.util.concurrent.CompletionException: java.lang.RuntimeException: Exception created by orgFuture
* ...
* Caused by: java.lang.RuntimeException: Exception created by orgFuture
* ...
* Program Run Failed
*/
@Test
public void exceptionallyTest() throws ExecutionException, InterruptedException {
//
CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("Current thread name: " + Thread.currentThread().getName());
throw new RuntimeException("Exception created by orgFuture");
});
//
CompletableFuture<String> exceptionallyFuture = orgFuture.exceptionally((e) -> {
e.printStackTrace();
return "Program Run Failed";
});
System.out.println(exceptionallyFuture.get());
}
3.5 whenComplete
CompletableFuture的whenComplete方法表示,某个任务执行完成后,执行的回调方法,无返回值;
并且whenComplete方法返回的CompletableFuture的result是上个任务的结果。
Demo:
whenComplete
/**
* 5. whenComplete
* CompletableFuturewhenComplete
* whenCompleteCompletableFutureresult
* <p>
* Result:
* Current Thread Name: ForkJoinPool.commonPool-worker-19
* Current Thread Name: ForkJoinPool.commonPool-worker-19
* The result of orgFuture: Result of orgFuture
* whenCompleteFuture Validation Completed
* Result of whenCompleteFuture: Result of orgFuture
*/
@Test
public void whenCompleteTest() throws ExecutionException, InterruptedException {
//
CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("Current Thread Name: " + Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "Result of orgFuture";
});
//
CompletableFuture<String> whenCompleteFuture = orgFuture.whenComplete((result, throwable) -> {
System.out.println("Current Thread Name: " + Thread.currentThread().getName());
System.out.println("The result of orgFuture: " + result);
if (result.equals("Result of orgFuture")) {
System.out.println("whenCompleteFuture Validation Completed");
} else {
System.out.println("whenCompleteFuture Validation Failed");
}
});
System.out.println("Result of whenCompleteFuture: " + whenCompleteFuture.get());
}
3.6 handle
CompletableFuture的handle方法表示,某个任务执行完成后,执行回调方法,并且是有返回值的;
并且handle方法返回的CompletableFuture的result是回调方法执行的结果。
不同的是 handle 是在任务完成后再执行,还可以处理异常的任务。
thenApply 只可以执行正常的任务,任务出现异常则不执行 thenApply 方法
Demo:
handle
/**
* 6. handle
* CompletableFuturehandle;
* handleCompletableFutureresult
* handle thenApply thenApply
* <p>
* Result:
* Current Thread Name: ForkJoinPool.commonPool-worker-19
* handleFuture Validation Completed
*/
@Test
public void handleTest() throws ExecutionException, InterruptedException {
//
CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("Current Thread Name: " + Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "orgFuture Result";
});
//
CompletableFuture<String> handleFuture = orgFuture.handle((result, throwable) -> {
if ("orgFuture Result".equals(result)){
return "handleFuture Validation Completed";
}else{
return "handleFuture Validation Failed";
}
});
System.out.println(handleFuture.get());
}
4 CompletableFuture多个任务组合处理
5 ForkJoinPool
ForkJoinPool和ThreadPoolExecutor都是继承自AbstractExecutorService抽象类,所以它和ThreadPoolExecutor的使用几乎没有多少区别,除了任务变成了
ForkJoinTask以外。
ForkJoinPool和ThreadPoolExecutor最主要的区别就是ForkJoinPool中每一个线程都有属于自己的队列,
当某个线程队列任务全部执行完了时,会通过"窃取工作"从别的线程队列中取出一个任务进行执行。
具体的策略就是每一个线程维护一个自己的队列,先进后出(FILO)将任务塞到队列的头部,
执行任务时从队列头部取出任务执行。其他线程从队列尾部窃取任务执行。减少阻塞消耗,特别适用于计算型任务。