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() 方法来获取任务的执行结果。
posted on 2023-04-05 21:16  colorfulworld  阅读(53)  评论(0)    收藏  举报