spring中的异步操作

1.Async

用于不需要返回值,通过注解来异步执行耗时操作;如果没有配置线程池,使用默认的线程池;

2.ExecutorService

1>对于不需要返回值的,直接调用execute方法即可;

public static void main(String[] args) {
        ExecutorService executorService= Executors.newSingleThreadExecutor();

        executorService.execute(()->{
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("ddd");
        });
    }

2>需要等待返回值的

 public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService= Executors.newSingleThreadExecutor();
        Future<Double> test = executorService.submit(() -> {
            System.out.println(Thread.currentThread() + " start,time->" + System.currentTimeMillis());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
            if (false) {
                throw new RuntimeException("test");
            } else {
                System.out.println(Thread.currentThread() + " exit,time->" + System.currentTimeMillis());
            }
            return 1.2;
        });
        System.out.println(test.get());

    }

另外,还提供invokeAll,提供批量的提交调用;

3.CompletableFuture

可以进行更复杂的多个异步操作,并且协调之间的先后顺序;

1>runAsync和supplyAcync创建子任务

runAsync提供无返回结果的任务;

supplyAcync提供有返回结果的任务;

注意,某些特别耗时的异步任务可能很浪费时间,因此强烈建议针对每个业务使用自己的线程池;如果不设置的话,使用系统默认线程池;

 public static void main(String[] args) throws ExecutionException, InterruptedException {
        try {
            runAsyncDemo();
            supplyAsyncDemo();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void runAsyncDemo() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("run end...");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        //等待异步任务执行完成,限时等待2秒
        future.get(2, TimeUnit.SECONDS);
    }

    //创建一个无消耗值(无输入值)、有返回值的异步子任务
    public static void supplyAsyncDemo() throws Exception {
        CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
            long start = System.currentTimeMillis();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("run end...");
            return System.currentTimeMillis() - start;
        });
        //等待异步任务执行完成,限时等待2秒
        long time = future.get(2, TimeUnit.SECONDS);
        System.out.println("异步执行耗时(秒):" + time / 1000);
    }

这两个方法,也可以传入一个线程池,通过线程池来执行;如果没有线程池,使用默认的ForkJoinPool.commonPool()来执行,默认的线程数是cpu的核数;

执行完成之后的回调,可以使用几种方式:

//设置子任务完成时的回调钩子
public CompletableFuture<T> whenComplete(
    BiConsumer<? super T, ? super Throwable> action)
//设置子任务完成时的回调钩子,可能不在同一线程执行
public CompletableFuture<T> whenCompleteAsync(
    BiConsumer<? super T, ? super Throwable> action)
//设置子任务完成时的回调钩子,提交给线程池executor执行
public CompletableFuture<T> whenCompleteAsync(
    BiConsumer<? super T, ? super Throwable> action, Executor executor) 
//设置异常处理的回调钩子
public CompletableFuture<T> exceptionally(
        Function<Throwable, ? extends T> fn)
public class CompletableFutureDemo1 {
    public static void whenCompleteDemo() throws Exception {
        //创建异步任务
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                //模拟执行一秒
                sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()+":抛出异常");
            throw new RuntimeException(Thread.currentThread().getName()+":发生异常");
        });
        //设置异步任务执行完成后的回调钩子
        future.whenComplete(new BiConsumer<Void, Throwable>() {
            @Override
            public void accept(Void unused, Throwable throwable) {
                System.out.println(Thread.currentThread().getName()+":执行完成!");
            }
        });

        //设置异步任务发生异常后的回调钩子
        future.exceptionally(new Function<Throwable, Void>() {
            @Override
            public Void apply(Throwable throwable) {
                System.out.println(Thread.currentThread().getName()+":执行失败!" + throwable.getMessage());
                return null;
            }
        });
    }

    public static void main(String[] args) throws Exception {
        whenCompleteDemo();
        sleep(2000);
    }
}

执行结果

ForkJoinPool.commonPool-worker-9:抛出异常
ForkJoinPool.commonPool-worker-9:执行失败!java.lang.RuntimeException: ForkJoinPool.commonPool-worker-9:发生异常
ForkJoinPool.commonPool-worker-9:执行完成!

发生异常时,先执行eceptionally中的,再执行whenComplete里面的方法;

在调用get方法时,如果异步任务中抛出异常,那么get方法也会异常;

也可以使用handler来处理

 //创建异步任务
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                //模拟执行一秒
                sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()+":抛出异常");
            throw new RuntimeException(Thread.currentThread().getName()+":发生异常");
        });
        future.handle(new BiFunction<Void, Throwable, Object>() {
            @Override
            public Object apply(Void unused, Throwable throwable) {
                if (throwable == null) {
                    System.out.println(Thread.currentThread().getName()+":没有发生异常!");
                } else {
                    System.out.println(Thread.currentThread().getName()+":sorry,发生了异常!"+throwable.getMessage());
                }
                return null;
            }
        });

异步任务之间,可以串行执行

//后一个任务与前一个任务在同一个线程中执行
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) 
//后一个任务与前一个任务不在同一个线程中执行
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn) 
//后一个任务在指定的executor线程池中执行
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
public static void whenCompleteDemo() throws Exception {
        //创建异步任务
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                //模拟执行一秒
                sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        future.thenApply(new Function<Void, Object>() {
            @Override
            public Object apply(Void unused) {
                System.out.println("sss");
                return null;
            }
        });
    }

注意,thenApply如果前面一个任务抛出异常,这个任务是不会执行的;前面一个任务的返回结果会传递到第二个任务里面,作为参数;另外还有thenRun方法,只要前面一个执行完成,后面一个就开始执行;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值