一、简介

应用场景    

   同步:同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果。

   异步: 异步调用则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕;而是继续执行下面的流程。例如, 在某个调用中,需要顺序调用 A, B, C三个过程方法;如他们都是同步调用,则需要将他们都顺序执行完毕之后,方算作过程执行完毕; 如B为一个异步的调用方法,则在执行完A之后,调用B,并不等待B完成,而是执行开始调用C,待C执行完毕之后,就意味着这个过程执行完毕了。在Java中,一般在处理类似的场景之时,都是基于创建独立的线程去完成相应的异步调用逻辑,通过主线程和不同的业务子线程之间的执行流程,从而在启动独立的线程之后,主线程继续执行而不会产生停滞等待的情况。

Spring 已经实现的线程池

1. SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,默认每次调用都会创建一个新的线程。
2. SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方。
3. ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类。
4. SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz使用,才需要使用此类。
5. ThreadPoolTaskExecutor :最常使用,推荐。 其实质是对java.util.concurrent.ThreadPoolExecutor的包装。

异步的方法有:

1. 最简单的异步调用,返回值为void
2. 带参数的异步调用,异步方法可以传入参数
3. 存在返回值,常调用返回Future

例:无返回值异步方法

@Async
    public void testAsyncService() {
        System.out.println("thread:" + Thread.currentThread().getId()+"execute no return value");
    }
    @GetMapping("/testNoReturnAsync")
    @ResponseBody
    public String testNoreturnAsync() {
        System.out.println("begin testAsync thread:" + Thread.currentThread().getId()+"execute no return value");
        asyncTestService.testAsyncService();
        System.out.println("end testAsync thread:" + Thread.currentThread().getId()+"execute no return value");
        return "testAsync";
    }

返回结果:

begin testAsync thread:181execute no return value
end testAsync thread:181execute no return value
thread:192execute no return value

有返回值异步方法

@Async
    public Future<String> testReturnAsyncService() {
        try {
            
            System.out.println("thread:" + Thread.currentThread().getId()+"execute return value");
            return new AsyncResult<String>("nihao");
        } catch(Throwable t) {
            t.printStackTrace();
        }
        return null;
    }
    @GetMapping("/testReturnAsync")
    @ResponseBody
    public String testReturnAsync() throws Exception {
        System.out.println("begin testAsync thread:" + Thread.currentThread().getId()+":execute return value");
        Future<String> future = asyncTestService.testReturnAsyncService();
        String result = future.get();
        System.out.println("end testAsync thread:" + Thread.currentThread().getId()+":execute return value");
        return result;
    }

返回结果:

begin testAsync thread:179:execute return value
thread:191execute return value
end testAsync thread:179:execute return value

 二、异常处理

仅用于无返回值的异步处理,有返回值需要自己在异步方法里处理异常。默认使用SimpleAsyncUncaughtExceptionHandler异常处理策略,自定义异常需实现AsyncUncaughtExceptionHandler 接口,同时注册到asyncconfigurer上去,asyncconfigurer还可注册自定义线程池

@Configuration
public class AsyncConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.initialize();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomerExceptionHandler();
    }
}
public class CustomerExceptionHandler implements AsyncUncaughtExceptionHandler {
    @Override
    public void handleUncaughtException(Throwable t, Method m,
            Object... obj) {
        System.out.println("Exception message -" + t.getMessage());
        System.out.println("Method name - " + m.getName());
        for(Object param : obj) {
            System.out.println("Parameter value - " + param);
        }
    }
}

打印:

Exception message -/ by zero
Method name - testAsyncService