Spring配置文件
配置文件的话有两种方式一种是精简式:
直接在applicationContext.xml中加入开启异步并添加task的命名空间
<task:executor id="WhifExecutor" pool-size="10"/>
<task:annotation-driven executor="WhifExecutor" />
xmlns:task="http://www.springframework.org/schema/task"http://www.springframework.org/schema/taskhttp://www.springframework.org/schema/task/spring-task.xsd
这样好处是简单快速,缺点是线程池配置简单,线程创建不能定时关闭。
所以我推荐下面这种,定义一个线程池,然后引入。其实两种方法原理是一样只不过下面这种只是线程池配置更加详细,线程在空闲后会根据存活时间配置进行关闭。
在applicationContext.xml同目录下创建文件threadPool.xml内容如下,然后在applicationContext.xml中引入threadPool.xml:<import resource="threadPool.xml" />
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<!-- 开启异步,并引入线程池 -->
<task:annotation-driven executor="threadPool" />
<!-- 定义线程池 -->
<bean id="threadPool"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数,默认为1 -->
<property name="corePoolSize" value="5" />
<!-- 最大线程数,默认为Integer.MAX_VALUE -->
<property name="maxPoolSize" value="20" />
<!-- 队列最大长度,一般需要设置值>=notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE -->
<property name="queueCapacity" value="500" />
<!-- 线程池维护线程所允许的空闲时间,默认为60s -->
<property name="keepAliveSeconds" value="30" />
<!-- 完成任务自动关闭 , 默认为false-->
<property name="waitForTasksToCompleteOnShutdown" value="true" />
<!-- 核心线程超时退出,默认为false -->
<property name="allowCoreThreadTimeOut" value="true" />
<!-- 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者 -->
<property name="rejectedExecutionHandler">
<!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常 -->
<!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 -->
<!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
<!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
</beans>
SpringBoot则是添加@EnableAsync注解
@EnableAsync
@SpringBootApplication
@ServletComponentScan
@MapperScan("com.cmc.schedule.model.mapper") //配置扫描mapper接口的地址
public class NLPApplication extends SpringBootServletInitializer {
//不使用springboot内嵌tomcat启动方式
@Override
protected SpringApplicationBuilder configure(
SpringApplicationBuilder application) {
return application.sources(NLPApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(NLPApplication.class, args);
}
//默认使用fastjson解析
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fastConverter.setFastJsonConfig(fastJsonConfig);
HttpMessageConverter<?> converter = fastConverter;
return new HttpMessageConverters(converter);
}
}
这一步Spring和SpringBoot都是一样的,创建一个异步方法的类
package com.cmc.tst;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Component;/**
* @Component 注解必须要有,否则无法将此bean注入
* 当然也可以使用其他的注解,只要可以装配就行
*
* @author chenmc
* @date 2017年9月4日 下午3:38:29
*/@Componentpublic class MyAsync { /**
* @Async 表明这是一个异步方法,也就是说当调用这个方法时,
* spring会创建一条线程来执行这个方法。
* 注意:不能使用static来修饰此方法,否则@Async无效
*
* @author chenmc
* @date 2017年9月4日 下午3:34:24
*/
@Async
public void asyncMethod(){
System.out.println(Thread.currentThread().getName());
}
}
测试调用异步方法,我这里使用的是JUnit4测试
@Autowired
MyAsync async;
@Test
public void test() {
System.out.println(Thread.currentThread().getName() + "start"); //MyAsync async = new MyAsync(); //自己new出来的对象@Async将无效,必须要spring注入的
async.asyncMethod(); try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "end");
}
总结
这里总结一下@Async注解无效的可能点
一、异步方法使用static修饰
二、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
三、测试异步方法不能与异步方法在同一个类中
四、测试类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
五、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解