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
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
参考文献:
https://blog.csdn.net/weixin_42311088/article/details/114921168
https://blog.csdn.net/jiayoubaobei2/article/details/127879719
submit(Callable task):这个方法的参数是一个 Callable 接口,它只有一个 call() 方法,并且这个方法是有返回值的,所以这个方法返回的 Future 对象可以通过调用其 get() 方法来获取任务的执行结果。