@Async是spring提供给用户起异步线程的注解,可以使使用该注解的方法变成一个异步方法,从而提高代码进行速度。
1.@Async使用需要的配置:
package com.zqsign.wesign.config;
import java.util.concurrent.Executor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
public class ExecutorConfig {
/** 初始线程数. */
private int corePoolSize = 7;
/** 最大线程数. */
private int maxPoolSize = 200;
/** 阻塞队列大小. */
private int queueCapacity = 100;
@Bean
public Executor signingAsync() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix("signingAsyncExecutor-");
executor.initialize();
return executor;
}
public int getCorePoolSize() {
return corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public int getQueueCapacity() {
return queueCapacity;
}
public void setQueueCapacity(int queueCapacity) {
this.queueCapacity = queueCapacity;
}
}
重点在于@EnableAsync这个注解,此时就可以使用@Async(“signingAsync”)注解来实现异步方法调用了。但还是有一些坑的:
同一个类中调用的坑:
public ContractResultInfo batchContractSignByKeyword(String interfaceCode,String conOrderNo,
List<SignContractVo> signContractVoList) {
for (int i = 0; i < 10; i++) {
batchContractKeywordSign(null);
}
return null;
}
@Async("signingAsync")
public void batchContractKeywordSign(SignContractVo signContractVo) {
logger.info("batchContractKeywordSign的线程名称:" + Thread.currentThread().getName());
}
此俩方法在同一个类中,为了方便省略了业务代码。由batchContractSignByKeyword调用
batchContractKeywordSign,被调用的方法batchContractKeywordSign是想实现一个异步调用的,并且多次调用此方法,臆想是启用线程池中的多个线程执行,但看实际效果:
@Test
public void asynTest1() {
contractServiceImpl.batchContractSignByKeyword("", "", null);
}
2019-06-19 14:44:06 INFO - <batchContractKeywordSign的线程名称:main>
2019-06-19 14:44:06 INFO - <batchContractKeywordSign的线程名称:main>
2019-06-19 14:44:06 INFO - <batchContractKeywordSign的线程名称:main>
2019-06-19 14:44:06 INFO - <batchContractKeywordSign的线程名称:main>
2019-06-19 14:44:06 INFO - <batchContractKeywordSign的线程名称:main>
2019-06-19 14:44:06 INFO - <batchContractKeywordSign的线程名称:main>
2019-06-19 14:44:06 INFO - <batchContractKeywordSign的线程名称:main>
2019-06-19 14:44:06 INFO - <batchContractKeywordSign的线程名称:main>
2019-06-19 14:44:06 INFO - <batchContractKeywordSign的线程名称:main>
2019-06-19 14:44:06 INFO - <batchContractKeywordSign的线程名称:main>
并没有实现异步,因为线程名称还是主线程main,后来发现是AOP织入时因为第一个方法不需要代理,所以被调用的方法就加不上代理了。然后解决这问题就把第一个方法也写成异步的:
@Async(“signingAsync”)
public ContractResultInfo batchContractSignByKeyword(String interfaceCode,String conOrderNo,
List signContractVoList) {
for (int i = 0; i < 10; i++) {
batchContractKeywordSign(null);
}
return null;
}
@Async(“signingAsync”)
public void batchContractKeywordSign(SignContractVo signContractVo) {
logger.info(“batchContractKeywordSign的线程名称:” + Thread.currentThread().getName());
}
测试输出:
2019-06-19 15:04:47 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:04:47 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:04:47 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:04:47 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:04:47 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:04:47 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:04:47 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:04:47 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:04:47 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:04:47 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
发现虽然使用的异步而且也是从线程池里拿的,但是一个线程,说明只有batchContractSignByKeyword这个方法是异步的,而被调用的方法batchContractKeywordSign不是,这不是我想要达到的效果,所以然后又想了一中方法才真正实现:专门建一个类来做异步方法处理,代码跟上面是一样的只是把被调用的方法放到了一个专门建的类中:
测试输出:
2019-06-19 15:10:56 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-2>
2019-06-19 15:10:56 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:10:56 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-4>
2019-06-19 15:10:56 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:10:56 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-4>
2019-06-19 15:10:56 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-1>
2019-06-19 15:10:56 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-3>
2019-06-19 15:10:56 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-6>
2019-06-19 15:10:56 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-5>
2019-06-19 15:10:56 INFO - - <batchContractKeywordSign的线程名称:signingAsyncExecutor-7>
如果是java1.8的话,有一种更方便的写法:
public ContractResultInfo batchContractSignByKeyword(String interfaceCode,String conOrderNo,
List signContractVoList) {
for (int i = 0; i < 10; i++) {
CompletableFuture.runAsync(()->{
batchContractKeywordSign(null);
}, signingAsync);
}
return null;
}
public void batchContractKeywordSign(SignContractVo signContractVo) {
logger.info(“batchContractKeywordSign的线程名称:” + Thread.currentThread().getName());
}
@Test
public void asynTest1() {
contractServiceImpl.batchContractSignByKeyword("", “”, null);
}
此时就不需要用到@Async注解了,CompletableFuture类是java1.8新加的,专门用来处理异步各种场景。