记录一次使用@Async的经历

@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新加的,专门用来处理异步各种场景。

猜你喜欢

转载自blog.csdn.net/shidebin/article/details/92834533