Spring Async异步线程
TaskExecutor
Spring异步线程池的接口类,其实质是java.util.concurrent.Executor
Spring 已经实现的异常线程池:
- SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。
- SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方
- ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类
- SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz使用,才需要使用此类
- ThreadPoolTaskExecutor :最常使用,推荐。 其实质是对java.util.concurrent.ThreadPoolExecutor的包装
@Async
spring对过@Async定义异步任务
异步的方法有3种
- 最简单的异步调用,返回值为void
- 带参数的异步调用 异步方法可以传入参数
- 异常调用返回Future
详细见代码:
package com.lay.spring.async.service;
import org.springframework.scheduling.annotation.AsyncResult;
import java.util.concurrent.Future;
/**
* @Description:
* @Author: lay
* @Date: Created in 14:07 2019/1/10
* @Modified By:IntelliJ IDEA
*/
public interface AsyncService {
/**
* 简单的异步调用返回值为void
*/
public void asyncInvokeSimple();
/**
* 带参数的异步调用,异步方法可以传入参数
* 对于返回值是void,异常会被AsyncUncaughtExceptionHandler处理
* @param param
*/
public void asyncInvokeWtihParameter(String param);
/**
* 调用异常返回Future
* 对于返回值是Future,不会被AsyncUncaughtExceptionHandler处理,需要我们在方法中捕获异常并处理
* 或者在调用的Future.get时候捕获异常进行处理
* @param i
* @return
*/
public Future<String> asyncInvokeReturnFuture(int i);
/**
* 通过AsyncResult捕获异常(有返回值)
* AsyncResult是Future接口的子类,所以也可以通过future.get()获取返回值的时候捕获ExcecutionException
* @param i
* @return
*/
public AsyncResult<String> asyncInvokeWithResult(int i);
}
具体实现类
package com.lay.spring.async.service.impl;
import com.lay.spring.async.service.AsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
/**
* @Description:
* @Author: lay
* @Date: Created in 14:12 2019/1/10
* @Modified By:IntelliJ IDEA
*/
@Service
@Async("async-Executor")
public class AsyncServiceImpl implements AsyncService {
private static final Logger log= LoggerFactory.getLogger(AsyncServiceImpl.class);
@Override
public void asyncInvokeSimple() {
log.info("asyncInvokeSimple,线程{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId());
}
@Override
public void asyncInvokeWtihParameter(String param) {
log.info("asyncInvokeWtihParameter,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),param);
}
@Override
public Future<String> asyncInvokeReturnFuture(int i) {
log.info("asyncInvokeReturnFuture,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),i);
Future<String> future=null;
try {
Thread.sleep(1000L);
future=new AsyncResult<>("success:"+i);
}catch (InterruptedException e){
future=new AsyncResult<>("error");
}
return future;
}
@Override
public AsyncResult<String> asyncInvokeWithResult(int i) {
log.info("asyncInvokeWithResult,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),i);
return new AsyncResult<>("success:"+i);
}
}
Spring 开启异步配置
Spring有两种方法启动配置
- 注解
- XML
通过注解实现
要启动异常方法还需要以下配置
- @EnableAsync 此注解开户异步调用功能
- public AsyncTaskExecutor taskExecutor() 方法自定义自己的线程池,线程池前缀”Anno-Executor”。如果不定义,则使用系统默认的线程池。
package com.lay.spring.async.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* @Description:
* @Author: lay
* @Date: Created in 15:01 2019/1/10
* @Modified By:IntelliJ IDEA
*/
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean("async-Executor")
public AsyncTaskExecutor taskExecutor(){
ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("Async-Executor");
executor.setMaxPoolSize(30);
executor.setQueueCapacity(1000);
executor.setCorePoolSize(10);
executor.initialize();
return executor;
}
}
通过XML实现
<!-- 等价于 @EnableAsync, executor指定线程池 -->
<task:annotation-driven executor="xmlExecutor"/>
<!-- id指定线程池产生线程名称的前缀 -->
<task:executor
id="xmlExecutor"
pool-size="5-25"
queue-capacity="100"
keep-alive="120"
rejection-policy="CALLER_RUNS"/>
测试类
package com.lay.spring.async;
import com.lay.spring.async.service.AsyncService;
import com.sun.media.jfxmedia.logging.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* @Description:
* @Author: lay
* @Date: Created in 15:03 2019/1/10
* @Modified By:IntelliJ IDEA
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class AsnycTest {
@Autowired
private AsyncService asyncService;
@Test
public void asyncTest(){
Future<String> future=asyncService.asyncInvokeReturnFuture(100);
asyncService.asyncInvokeSimple();
asyncService.asyncInvokeWtihParameter("async-test");
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("InterruptedException ");
} catch (ExecutionException e) {
e.printStackTrace();
System.out.println("ExecutionException ");
}
System.out.println("done");
}
}
异步方法的异常处理
在调用方法时,可能出现方法中抛出异常的情况。在异步中主要有有两种异常处理方法:
- 对于方法返回值是Futrue的异步方法: a) 一种是在调用future的get时捕获异常; b) 在异常方法中直接捕获异常
- 对于返回值是void的异步方法:通过AsyncUncaughtExceptionHandler处理异常
package com.lay.spring.async.service.impl;
import com.lay.spring.async.service.AsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
/**
* @Description:
* @Author: lay
* @Date: Created in 14:12 2019/1/10
* @Modified By:IntelliJ IDEA
*/
@Service
@Async("async-Executor")
public class AsyncServiceImpl implements AsyncService {
private static final Logger log= LoggerFactory.getLogger(AsyncServiceImpl.class);
@Override
public void asyncInvokeSimple() {
log.info("asyncInvokeSimple,线程{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId());
}
@Override
public void asyncInvokeWtihParameter(String param) {
log.info("asyncInvokeWtihParameter,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),param);
throw new IllegalArgumentException(param);
}
@Override
public Future<String> asyncInvokeReturnFuture(int i) {
log.info("asyncInvokeReturnFuture,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),i);
Future<String> future=null;
try {
Thread.sleep(1000L);
future=new AsyncResult<>("success:"+i);
throw new IllegalArgumentException("a");
}catch (InterruptedException e){
future=new AsyncResult<>("error");
}
return future;
}
@Override
public AsyncResult<String> asyncInvokeWithResult(int i) {
log.info("asyncInvokeWithResult,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),i);
return new AsyncResult<>("success:"+i);
}
}
实现AsyncConfigurer接口对异常线程池更加细粒度的控制
- 创建线程自己的线程池
- 对void方法抛出的异常处理的类AsyncUncaughtExceptionHandler
package com.lay.spring.async.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
/**
* @Description:
* @Author: lay
* @Date: Created in 15:39 2019/1/10
* @Modified By:IntelliJ IDEA
*/
@Configuration
public class MyAsyncConfig implements AsyncConfigurer {
private static final Logger log= LoggerFactory.getLogger(MyAsyncConfig.class);
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
threadPool.setCorePoolSize(1);
threadPool.setMaxPoolSize(1);
threadPool.setWaitForTasksToCompleteOnShutdown(true);
threadPool.setAwaitTerminationSeconds(60 * 15);
threadPool.setThreadNamePrefix("MyAsync-");
threadPool.initialize();
return threadPool;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncExceptionHandler();
}
class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
log.info("Exception message - " + throwable.getMessage());
log.info("Method name - " + method.getName());
for (Object param : objects) {
log.info("Parameter value - " + param);
}
}
}
}