技能需要反复操练

技·@Async注解

准备

springboot项目一个。

开启@Async功能

@EnableAsync // 启动类上加上此注解
@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(ExperimentalApplication.class, args);
	}

}
@Service
public class AsyncService {
	@Async // 使用注解
	public void async() {
		// 在此处补充打印当前线程信息的代码
	}
}
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ApplicationTests {

	@Test
	void contextLoads() {
		// 在你的测试单元里面测试你的service
	}

}

观察控制台的打印日志并记录,此时所看到的线程信息即为@Async默认使用线程。

定义自己的线程池

1.实现AsyncConfigurer接口
org.springframework.scheduling.annotation.AsyncConfigurer

@EnableAsync // 配置在配置类上,可以将启动类上的注解去掉了
@Configuration
public class AsyncConfig implements AsyncConfigurer {
	@Bean
	public ThreadPoolTaskExecutor asyncExecutor() {
		// spring线程池各个方法的作用自行学习,按需配置。
		ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
		executor.setCorePoolSize(5);
		executor.setMaxPoolSize(10);
		executor.setKeepAliveSeconds(60);
		executor.setQueueCapacity(99999);
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		executor.setThreadNamePrefix("async-service-");// 看这里①
		executor.setAwaitTerminationSeconds(60);
		executor.setWaitForTasksToCompleteOnShutdown(true);
		return executor;
	}
	@Override
	public Executor getAsyncExecutor() {
		return asyncExecutor();
	}
	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return (ex,method,params)->System.out.println(String.format("执行异步方法:%s错误,%s", params, ex)); // 在此演示中不是重点,请随意。
	}
}

启动测试观察打印结果,不出意外你应该会看到和①处长得很像的东西,证明我们配置的线程池起作用了。

2.继承AsyncConfigurerSupport
org.springframework.scheduling.annotation.AsyncConfigurerSupport

将AsyncConfigurer换成AsyncConfigurerSupport即可。

3.通过ThreadPoolExecutor定义线程池

@EnableAsync
@Configuration
public class AsyncConfig {
    // 这个时候需要将beanName设置为“taskExecutor”
	@Bean(name=AsyncExecutionAspectSupport.DEFAULT_TASK_EXECUTOR_BEAN_NAME)
	public Executor asyncExecutor1() {
		return new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2),
				new ThreadFactory() {// 自定义一个线程工厂只是为了给线程取一个我们自己的名字,别在意细节。
					@Override
					public Thread newThread(Runnable r) {
						return new Thread(r, "async-service-" + r.hashCode());
					}
				});
	}
}

4.通过ThreadPoolTaskExecutor创建线程池

@EnableAsync
@Configuration
public class AsyncConfig{ // 就是说实际上可以不用实现AsyncConfigurer
	@Bean // 这个时候可以不指定线程名称的
	public Executor asyncExecutor() {
		ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
		executor.setCorePoolSize(5);
		executor.setMaxPoolSize(10);
		executor.setKeepAliveSeconds(60);
		executor.setQueueCapacity(99999);
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		executor.setThreadNamePrefix("async-service-");
		executor.setAwaitTerminationSeconds(60);
		executor.setWaitForTasksToCompleteOnShutdown(true);
		return executor;
	}
}

另外@Async(“线程池名称”),指定value使用自己定义的线程池。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐