提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
1 异步@Async详解
1.1 引言
- 在java中异步线程很重要,比如在业务流处理时,需要通知硬件设备,发短信通知用户,或者需要上传一些图片资源到其他服务器这种耗时的操作,在主线程里处理会阻塞整理流程,而且我们也不需要等待处理结果之后再进行下一步操作,这时候就可以使用异步线程进行处理,这样主线程不会因为这些耗时的操作而阻塞,保证主线程的流程可以正常进行。
1.2 异步说明和原理
1.3 @Async使用
Spring中启用@Async:
- @Async注解在使用时,如果不指定线程池的名称,则使用Spring默认的线程池,Spring默认的线程池为SimpleAsyncTaskExecutor。
- 方法上一旦标记了这个@Async注解,当其它线程调用这个方法时,就会开启一个新的子线程去异步处理该业务逻辑。
1.3.1 启动类中增加@EnableAsync
- 以Spring boot为例,启动类中增加@EnableAsync:
@EnableAsync
@SpringBootApplication
public class ManageApplication {
//...
}
1.3.2 方法上加@Async注解
@Component
public class MyAsyncTask {
@Async
public void asyncCpsItemImportTask(Long platformId, String jsonList){
//...具体业务逻辑
}
}
1.4 @Async异步线程池
1.4.1 默认线程池
上面的配置会启用默认的线程池/执行器,异步执行指定的方法。
Spring默认的线程池的默认配置:
默认核心线程数:8,
最大线程数:Integet.MAX_VALUE,
队列使用LinkedBlockingQueue,
容量是:Integet.MAX_VALUE,
空闲线程保留时间:60s,
线程池拒绝策略:AbortPolicy
缺点:从最大线程数的配置上,相信看到问题:并发情况下,会无限创建线程 造成 oom
默认线程池的上述缺陷如何解决:答案是,自定义配置参数就可以了
1.4.2 在配置文件中配置
spring:
task:
execution:
pool:
max-size: 6
core-size: 3
keep-alive: 3s
queue-capacity: 1000
thread-name-prefix: name
1.4.3 自定义线程池
在业务场景中,有时需要使用自己定义的执行器来跑异步的业务逻辑,那该怎么办呢?答案是,自定义线程池。
1 编写配置类
@Configuration
@Data
public class ExecutorConfig{
//核心线程
private int corePoolSize;
//最大线程
private int maxPoolSize;
//队列容量
private int queueCapacity;
//保持时间
private int keepAliveSeconds;
//名称前缀
private String preFix;
@Bean("MyExecutor")
public Executor myExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveSeconds);
executor.setThreadNamePrefix(preFix);
executor.setRejectedExecutionHandler( new ThreadPoolExecutor.AbortPolicy());
executor.initialize();
return executor;
}
}
2 使用自定义线程池
在方法上的@Async注解处指定线程池名字:
@Component
public class MyAsyncTask {
@Async("MyExecutor") //使用自定义的线程池(执行器)
public void asyncCpsItemImportTask(Long platformId, String jsonList){
//...具体业务逻辑
}
}
1.4.4 Spring中的线程池(执行器)
1.5 异步中的事务和返回
1.6 异步不能回调问题
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mybatis.xml</param-value>
</context-param>
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>dev</param-value>
</context-param>
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>dev</param-value>
</context-param>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
1.7 失效情况分析