@Async 注解的使用和实现

news/2025/3/15 1:23:57/

@Async 注解的使用和实现

    • 1.使用
    • 2.实现
    • 3.自定义@Async 的线程池
      • 3.1 第一种方式
      • 3.2 第二种方式

1.使用

1.1 SpringBootApplication 启动类或者配置类中添加@EnableAsync 注解。
1.2 在需要异步执行的方法中加上@Async 注解。

注意:

@Async 注解应该用在“public”方法上。
@Async 注解所在的类应该被 Spring 容器管理。
@Async 注解作用的方法,被调用的时候需要被Spring动态代理到,同类方法不能直接用this.xxx()调用否则不生效。

@EnableAsync
@SpringBootApplication
public class DemoAsyncApplication {public static void main(String[] args) {SpringApplication.run(DemoAsyncApplication.class, args);}}
@Slf4j
@Service
public class AsyncService {@Asyncpublic void test(){try {TimeUnit.SECONDS.sleep(1);log.info(Thread.currentThread().getName()+"AsyncService");} catch (InterruptedException e) {throw new RuntimeException(e);}}}

2.实现

@Async 注解 的默认使用的是bean name为”taskExecutor“,核心线程数为8,最大线程数为Integer.MAX_VALUE,阻塞队列为LinkedBlockingQueue,阻塞队列的大小Integer.MAX_VALUE,为线程空闲超时时间为60秒。

public static class Pool {/*** Queue capacity. An unbounded capacity does not increase the pool and therefore* ignores the "max-size" property.*/private int queueCapacity = Integer.MAX_VALUE;/*** Core number of threads.*/private int coreSize = 8;/*** Maximum allowed number of threads. If tasks are filling up the queue, the pool* can expand up to that size to accommodate the load. Ignored if the queue is* unbounded.*/private int maxSize = Integer.MAX_VALUE;/*** Whether core threads are allowed to time out. This enables dynamic growing and* shrinking of the pool.*/private boolean allowCoreThreadTimeout = true;/*** Time limit for which threads may remain idle before being terminated.*/private Duration keepAlive = Duration.ofSeconds(60);

使用的默认线程是在配置类TaskExecutionAutoConfiguration 里配置的。

/*** {@link EnableAutoConfiguration Auto-configuration} for {@link TaskExecutor}.** @author Stephane Nicoll* @author Camille Vienot* @since 2.1.0*/
@ConditionalOnClass(ThreadPoolTaskExecutor.class)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(TaskExecutionProperties.class)
public class TaskExecutionAutoConfiguration {/*** Bean name of the application {@link TaskExecutor}.*/public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";@Bean@ConditionalOnMissingBeanpublic TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties,ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers,ObjectProvider<TaskDecorator> taskDecorator) {TaskExecutionProperties.Pool pool = properties.getPool();TaskExecutorBuilder builder = new TaskExecutorBuilder();builder = builder.queueCapacity(pool.getQueueCapacity());builder = builder.corePoolSize(pool.getCoreSize());builder = builder.maxPoolSize(pool.getMaxSize());builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());builder = builder.keepAlive(pool.getKeepAlive());Shutdown shutdown = properties.getShutdown();builder = builder.awaitTermination(shutdown.isAwaitTermination());builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());builder = builder.threadNamePrefix(properties.getThreadNamePrefix());builder = builder.customizers(taskExecutorCustomizers.orderedStream()::iterator);builder = builder.taskDecorator(taskDecorator.getIfUnique());return builder;}@Lazy@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })@ConditionalOnMissingBean(Executor.class)public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {return builder.build();}}

使用用线程池去执行任务:
AsyncExecutionAspectSupport.java

@Override@Nullablepublic Object invoke(final MethodInvocation invocation) throws Throwable {Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);if (executor == null) {throw new IllegalStateException("No executor specified and no default executor set on AsyncExecutionInterceptor either");}Callable<Object> task = () -> {try {Object result = invocation.proceed();if (result instanceof Future) {return ((Future<?>) result).get();}}catch (ExecutionException ex) {handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());}catch (Throwable ex) {handleError(ex, userDeclaredMethod, invocation.getArguments());}return null;};return doSubmit(task, executor, invocation.getMethod().getReturnType());}

获取线程池,先看注解的value是否有值,有值则根据bean 那么获取线程池,否则从默认的线程池中获取。

@Nullableprotected AsyncTaskExecutor determineAsyncExecutor(Method method) {AsyncTaskExecutor executor = this.executors.get(method);if (executor == null) {Executor targetExecutor;String qualifier = getExecutorQualifier(method);if (StringUtils.hasLength(qualifier)) {targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);}else {targetExecutor = this.defaultExecutor.get();}if (targetExecutor == null) {return null;}executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?(AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));this.executors.put(method, executor);}return executor;}

3.自定义@Async 的线程池

自定义@Async 的线程池有两种实现方式,第一种是自定义一个线程池,然后写在注解里 @Async(value = "asyncMarkValueExecutor");第二种是实现AsyncConfigurer接口,重写getAsyncExecutor()方法。

3.1 第一种方式

1.定义一个线程池,注入spring

    @Bean(name = "asyncMarkValueExecutor")public Executor asyncMarkValueExecutor(){ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(10);executor.setMaxPoolSize(1000);executor.setQueueCapacity(10000);executor.setThreadNamePrefix("async-thread-pool-");executor.initialize();return executor;}

2.将线程池的bean name加到注解里。

    @Async(value = "asyncMarkValueExecutor")public void test(){try {TimeUnit.SECONDS.sleep(1);log.info(Thread.currentThread().getName()+"AsyncService");} catch (InterruptedException e) {throw new RuntimeException(e);}}

3.2 第二种方式

实现AsyncConfigurer接口,重写getAsyncExecutor()方法。

@Configuration
public class MyConfig implements AsyncConfigurer {@Bean(name = "asyncExecutor")public Executor asyncExecutor(){ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(10);executor.setMaxPoolSize(2000);executor.setQueueCapacity(10000);executor.setThreadNamePrefix("my-thread-pool-");executor.initialize();return executor;}@Overridepublic Executor getAsyncExecutor() {return asyncExecutor();}
}

http://www.ppmy.cn/news/980316.html

相关文章

白话机器学习笔记(二)学习分类

分类用图形来解释&#xff0c;把他想象为有大小有方向带箭头的向量。 设权重向量为 w w w&#xff0c;虚线为使权重向量称为法线向量的直线。 直线的表达式为&#xff1a; w ⋅ x 0 w\cdot x0 w⋅x0 (两个向量的内积) 也可写为&#xff1a; w ⋅ x ∑ i 1 n w i x i w 1…

手机变局2023:一场瞄准产品和技术的“思维革命”

以折叠屏冲高端&#xff0c;已成为中国手机厂商们的共识。 在这个苹果未涉足的领域&#xff0c;国产手机厂商们加快脚步迭代推新&#xff0c;积极抢占机遇。但平心而论&#xff0c;虽然国产折叠屏机型众多&#xff0c;但市场上始终缺乏一款突破性的产品作为标杆&#xff0c;为…

白话机器学习笔记(一)学习回归

最小二乘法 定义模型 表达式&#xff1a; f θ ( x ) θ 0 θ 1 x f_\theta(x)\theta_0\theta_1x fθ​(x)θ0​θ1​x &#xff08;常用 θ \theta θ表示未知数、 f θ ( x ) f_\theta(x) fθ​(x)表示含有参数 θ \theta θ并且和变量 x x x相关的函数&#xff09; 目标…

Golang指针详解

要搞明白Go语言中的指针需要先知道3个概念&#xff1a;指针地址、指针类型和指针取值。 指针介绍 我们知道变量是用来存储数据的&#xff0c;变量的本质是给存储数据的内存地址起了一个好记的别名。比如我们定义了一个变量 a : 10 ,这个时候可以直接通过 a 这个变量来读取内存…

4EVERLAND 托管让 Permaweb 变得更容易!

在互联网托管领域&#xff0c;我们通常将其与存储和管理网站的服务联系起来。传统的 Web2 托管服务在集中式服务器模型上运行&#xff0c;其中网站文件和数据库存储在集中管理的服务器上。用户通过互联网访问网站。这种托管模式应用广泛&#xff0c;相对简单&#xff0c;适合很…

redis单线程速度又快

Redis之所以在单进程单线程的情况下能够如此快速&#xff0c;主要有以下几个方面的原因&#xff1a; 纯内存操作&#xff1a;Redis将数据存储在内存中&#xff0c;而不是磁盘上。内存的读写速度远高于磁盘&#xff0c;因此Redis能够以极快的速度进行数据的读写操作。 非阻塞I…

PHP百度小程序rtc-room组件token获取经历

【前言】 目前就职盘古网络集团&#xff0c;一名PHPer程序员。我们的主营业务是百度产品相关&#xff0c;所以最近有了一个百度小程序项目&#xff0c;涉及其音视频组件做直播。 开发文档 百度智能小程序文档 鉴权token 百度智能小程序文档 嗯&#xff0c;很好的功能。结果测…

Python 电商API 开发最佳实践

一、简介 当你打卡了一家北京最具有地中海特色的餐厅&#xff0c;当我们在餐厅点餐时&#xff0c;服务员会给我们一份菜单&#xff0c;菜单上列出了所有可供选择的菜品和饮料。我们可以在菜单上选择我们想要的食物和饮料&#xff0c;然后告诉服务员我们的选择。服务员会根据我…