1. Future
异步计算结果,提供了一些方法来检验任务是否完成,get()都是阻塞的。
1.1 Future接口方法:
// 取消任务 boolean cancel(boolean mayInterruptIfRunning); // 判断任务是否已取消 boolean isCancelled(); // 判断任务是否已结束 boolean isDone(); // 获得任务执行结果 get(); // 获得任务执行结果,支持超时 get(long timeout, TimeUnit unit);
1.2 Future获取任务结果
public Future<?> submit(Runnable task) { //参数Runnable接口的run()没有返回值,所以submit(Runnable task)返回的Future尽可以用来判断任务是否结束 } public <T> Future<T> submit(Runnable task, T result) { } public <T> Future<T> submit(Callable<T> task) { }
注意public<T> Future<T> submit(Runnable task, T result)这个方法,Runnable 接口的实现类 Task 声明了一个有参构造函数 Task(Result r) ,创建 Task 对象的时候传入了 result 对象,这样就能在类 Task 的 run() 方法中对 result 进行各种操作了。result 相当于主线程和子线程之间的桥梁,通过它主子线程可以共享数据。
submit(Callable task):这个方法的参数是一个 Callable 接口,它只有一个 call() 方法,并且这个方法是有返回值的,所以这个方法返回的 Future 对象可以通过调用其 get() 方法来获取任务的执行结果。
ExecutorService executorService=Executors.newSingleThreadExecutor(); Future<List<String>> future=executorService.submit(new Callable<List<String>>() { @Override public List<String> call() throws Exception { return callMethod(); } });
2. FutureTask
FutureTask实现了Runnable和Future接口
public class FutureTask<V> implements RunnableFuture<V> {...} public interface RunnableFuture<V> extends Runnable, Future<V> { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); }
由于FutureTask实现Runnable,所以可以作为任务提交给ThreadPoolExecutor,
// 创建FutureTask FutureTask<Integer> futureTask = new FutureTask<>(()-> 1); // 创建线程池 ExecutorService es = Executors.newCachedThreadPool(); // 提交FutureTask es.submit(futureTask); // 获取计算结果 Integer result = futureTask.get();
由于FutureTask实现Future,所以可以用来获取任务执行结果
public class TestSupplier { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask futureTask1=new FutureTask(new CallMongo1("futuretask1")); FutureTask futureTask2=new FutureTask(new CallMongo2("futuretask2")); Thread t1=new Thread(futureTask1); t1.start(); Thread t2=new Thread(futureTask2); t2.start(); System.out.println("f1 result:"+futureTask1.get()); System.out.println("f2 result:"+futureTask2.get()); } } @AllArgsConstructor class CallMongo1 implements Callable<String>{ String input; @Override public String call() throws Exception { Thread.sleep(2000); return input.concat("_callMongo1"); } } @AllArgsConstructor class CallMongo2 implements Callable<String>{ String input; @Override public String call() throws Exception { Thread.sleep(3000); return input.concat("_callMongo2"); } }
3. CompletableFuture
Future相较于CompletableFuture,它有如下缺点:
- 上一个Future结果不能传到下一个Future中使用,但CompletableFuture可以使用thenApply来实现这种链式调用
- Future get()是阻塞的
- 不支持多个Future合并,比如有3个Future并行执行,如果想所有的future运行结束后执行某个函数是无法通过future实现的
- Future api是没有异常处理结果的,不好进行问题定位
- CompletableFuture提供了异步函数式编程。可以通过回调方式处理计算结果,并且提供转换和组合CompletableFuture的方法
3.1 CompletableFuture创建方式
a) CompletableFuture < void > runAsync(Runnable runnable){ 异步的执行任务,由于是Runnable,所以没有返回值 b) CompletableFuture< void > runAsync(Runnable runnable, Executor executor) { 意思与上诉一致,可以自定义线程池 c) CompletableFuture< U > supplyAsync(Supplier< U > supplier) { Supplier 接口的 get() 方法是有返回值的。 d) CompletableFuture< U > supplyAsync(Supplier< U > supplier, Executor executor) { 可以自定义线程池
supplyAsync表示创建带返回值的异步任务的,相当于ExecutorService submit(Callable<T> task) 方法,runAsync表示创建无返回值的异步任务,相当于ExecutorService submit(Runnable task)方法,这两方法的效果跟submit是一样的
public class ComplatableFuturedemo { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorReRunnerService = Executors.newFixedThreadPool(1); String date="20230506"; String name="test"; CompletableFuture<String> result=CompletableFuture.supplyAsync(()->runAsync(date,name),executorReRunnerService); System.out.println(result.get()); } public static String runAsync(String date,String name){ return date.concat(name); } }
3.2 线程依赖
thenApply / thenApplyAsync
thenApply 表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中
public void test5() throws Exception { ForkJoinPool pool=new ForkJoinPool(); // 创建异步执行任务: CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{ System.out.println(Thread.currentThread()+" start job1,time->"+System.currentTimeMillis()); try { Thread.sleep(2000); } catch (InterruptedException e) { } System.out.println(Thread.currentThread()+" exit job1,time->"+System.currentTimeMillis()); return 1.2; },pool); //cf关联的异步任务的返回值作为方法入参,传入到thenApply的方法中 //thenApply这里实际创建了一个新的CompletableFuture实例 CompletableFuture<String> cf2=cf.thenApply((result)->{ System.out.println(Thread.currentThread()+" start job2,time->"+System.currentTimeMillis()); try { Thread.sleep(2000); } catch (InterruptedException e) { } System.out.println(Thread.currentThread()+" exit job2,time->"+System.currentTimeMillis()); return "test:"+result; }); System.out.println("main thread start cf.get(),time->"+System.currentTimeMillis()); //等待子任务执行完成 System.out.println("run result->"+cf.get()); System.out.println("main thread start cf2.get(),time->"+System.currentTimeMillis()); System.out.println("run result->"+cf2.get()); System.out.println("main thread exit,time->"+System.currentTimeMillis()); }
Thread[ForkJoinPool-1-worker-1,5,main] start job1,time->1668570856694
main thread start cf.get(),time->1668570856694
Thread[ForkJoinPool-1-worker-1,5,main] exit job1,time->1668570858705
Thread[ForkJoinPool-1-worker-1,5,main] start job2,time->1668570858705
run result->1.2
main thread start cf2.get(),time->1668570858706
Thread[ForkJoinPool-1-worker-1,5,main] exit job2,time->1668570860717
run result->test:1.2
main thread exit,time->1668570860717
3.3 消费处理结果 thenAccept
上边两个串行线程执行完成后的结果进行消费,但thenAccept()是没有返回结果的
public class Test { 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); } }); } }
3.4 异常结果处理 exceptionally
exceptionally异常处理
public class Test { 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()); } }
3.5 最终结果处理 handle
handle函数是在最后使用,可以做类似thenAccept的结果处理,也可以做类似exceptionally异常结果处理。但注意handle是有结果返回的
public class Test { private static Integer num = 10; public static void main(String[] args) throws Exception { System.out.println("主线程开始"); CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { 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()); } }
3.6 具有依赖关系的CompletableFuture结果合并 thenCompose
thenCompose和thenApply很相似,但thenCompose是将上一个异步结果作为下一个异步操作的输入;而thenApply是将上一个异步处理结果直接在thenApply中进行结果处理并没有新建一个异步处理
public class Test { 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()); } }
3.7 没有依赖关系的CompletableFuture结果合并 thenCombine
public class Test { 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()); } }
3.8 合并所有的CompletableFuture任务 allOf
一系列独立的CompletableFuture, allOf里所有任务完成后再进行其他事情
public class alofDemo01 { public static void main(String[] args) throws ExecutionException, InterruptedException { CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { try { System.out.println("我已经执行了"); TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return "hello"; }); CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(2); System.out.println("我已经执行了第二次"); } catch (InterruptedException e) { e.printStackTrace(); } return "test"; }); CompletableFuture<Void> allOf = CompletableFuture.allOf(future, future1); allOf.thenRun(() -> { try { String s = future.get(); System.out.println(System.currentTimeMillis() + s); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } try { String s = future1.get(); System.out.println(System.currentTimeMillis() + s); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }); System.out.println("测试阻塞"); allOf.get(); } }
3.9 一系列独立CompletableFuture,其中某一个完成就会继续接下来处理 anyOf
public class alofDemo01 { public static void main(String[] args) throws ExecutionException, InterruptedException { CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { try { System.out.println("我已经执行了"); TimeUnit.SECONDS.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return "hello"; }); CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(2); System.out.println("我已经执行了第二次"); } catch (InterruptedException e) { e.printStackTrace(); } return "test"; }); CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future, future1); anyOf.handle((s, throwable) -> { System.out.println(s); return s; }); anyOf.get(); } }
参考文献:
https://blog.csdn.net/weixin_42311088/article/details/114921168
https://blog.csdn.net/jiayoubaobei2/article/details/127879719
https://blog.csdn.net/qq_34491508/article/details/131790704?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-8-131790704-blog-140893478.235^v43^control&spm=1001.2101.3001.4242.5&utm_relevant_index=10
submit(Callable task):这个方法的参数是一个 Callable 接口,它只有一个 call() 方法,并且这个方法是有返回值的,所以这个方法返回的 Future 对象可以通过调用其 get() 方法来获取任务的执行结果。
浙公网安备 33010602011771号