Spring @Async 注解的使用

Spring @Async 注解的使用

​ Spring中用@Async注解标记的方法,称为异步方法,它会在调用方的当前线程之外的独立的线程中执行。调用者将在调用时立即返回,方法的实际执行将提交给Spring TaskExecutor的任务中,由指定的线程池中的线程执行。

Spring 已经实现的线程池

​ 1、SimpleAsyncTaskExecutor:默认情况下每次调用都会创建一个新的线程,若系统中不断的创建线程,最终会导致系统占用内存过高,引发 OutOfMemoryError 错误。针对线程创建问题,SimpleAsyncTaskExecutor 提供了限流机制,通过 concurrencyLimit 属性来控制开关,当concurrencyLimit>=0 时开启限流机制,默认关闭限流机制即 concurrencyLimit = -1,当关闭情况下,会不断创建新的线程来处理任务。默认配置 SimpleAsyncTaskExecutor 并不是严格意义的线程池,达不到线程复用的功能。
​ 2、SyncTaskExecutor:没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方。
​ 3、ConcurrentTaskExecutorExecutor 的适配类,不推荐使用。如果 ThreadPoolTaskExecutor 不满足要求时,才考虑使用这个类。
​ 4、 SimpleThreadPoolTaskExecutor :是 QuartzSimpleThreadPool 的类。线程池同时被 quartz 和非 quartz使用,才需要使用此类。
​ 5、ThreadPoolTaskExecutor :推荐使用,其实质是对 java.util.concurrent.ThreadPoolExecutor 的包装。

@Async注解使用条件

​ 1、@Async 注解一般使用在方法上,如果使用在类上,这个类中所有方法都是异步执行的,如果方法上也有该注解,将覆盖类上的注解内容;
​ 2、@Async 注解使用在方法上,方法必须是 public 修饰的,且不能是 static 修饰的;
​ 3、@Async 注解使用在方法上,参数可以是任意类型的,但是方法的返回值必须是 void 或者Future 类型;
​ 4、默认情况下(即@EnableAsync注解的mode=AdviceMode.PROXY),同一个类内部没有使用@Async注解修饰的方法调用@Async注解修饰的方法,是不会异步执行的。如果想实现类内部自调用也可以异步,则需要切换@EnableAsync注解的mode=AdviceMode.ASPECTJ
​ 5、@Async注解是基于动态代理实现的;
​ 6、@Async 注解默认使用 SimpleAsyncTaskExecutor 作为线程池,推荐自定义ThreadPoolTaskExecutor

@Async注解的使用

​ 1、注册为bean组件

package com.jidi.springbootredis.config;

import com.jidi.springbootredis.exception.AsyncExceptionHandler;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Description @Async注解使用配置类
 * @Author jidi
 * @Email jidi_jidi@163.com
 * @Date 2021/8/1
 */

@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {=
    /**
     *  自定义线程池
     */
    @Bean("executor")
    public Executor executor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 线程池核心线程数量
        executor.setCorePoolSize(5);
        // 队列最大长度
        executor.setQueueCapacity(100);
        // 最大线程数量
        executor.setMaxPoolSize(5);
        // 线程池拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 线程名前缀
        executor.setThreadNamePrefix("async-");
        // 允许空闲时间
        executor.setKeepAliveSeconds(30);
        // 初始化
        executor.initialize();
        return executor;
    }


    /**
     *  如果有多个线程池,指定要使用的线程池
     */
    @Override
    public Executor getAsyncExecutor() {
        return executor();
    }


    /**
     *  指定异常处理
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler(){
        return new AsyncExceptionHandler();
    }
}

​ 2、自定义异常处理

package com.jidi.springbootredis.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import java.lang.reflect.Method;

/**
 * @Description @Async注解使用 自定义异常处理
 * @Author jidi
 * @Email jidi_jidi@163.com
 * @Date 2021/8/1
 */

@Slf4j
public class AsyncExceptionHandler extends SimpleAsyncUncaughtExceptionHandler {
    /**
     *  自定义异常处理逻辑
     */
    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... params) {
        StringBuilder info = new StringBuilder();
        String msg = throwable.getMessage() != null ? throwable.getMessage() : throwable.getClass().getSimpleName();
        info.append("出现异常:").append(msg).append(" methodName: " + method).append("\n");
        for (StackTraceElement stackTrace : throwable.getStackTrace()) {
            info.append(stackTrace.toString()).append("\n");
        }
        log.error(info.toString());
    }
}

​ 3、定义异步方法

package com.jidi.springbootredis.component;

import com.jidi.springbootredis.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.concurrent.Future;

/**
 * @Description 异步方法
 * @Author jidi
 * @Email jidi_jidi@163.com
 * @Date 2021/8/1
 */

@Component
public class AsyncComponent {
    @Autowired
    private UserService userService;

    /**
     * 无返回值的异步方法
     */
    @Async
    public void print(){
        System.out.println(Thread.currentThread().getName() + "执行了方法print()" + System.currentTimeMillis());
    }


    /**
     * 有返回值的异步方法
     */
    @Async
    public Future<Integer> asyncSquare(int x) {
        System.out.println("calling asyncSquare," + Thread.currentThread().getName() + "," + new Date());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("asyncSquare Finished," + Thread.currentThread().getName() + "," + new Date());
        return new AsyncResult<>(x + x);
    }
}

​ 4、测试

package com.jidi.springbootredis;

import com.jidi.springbootredis.component.AsyncComponent;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @Description @Async注解使用测试
 * @Author jidi
 * @Email jidi_jidi@163.com
 * @Date 2021/8/1
 */

@Slf4j
@SpringBootTest
public class AsyncTest {

    @Autowired
    private AsyncComponent asyncComponent;

    /**
     * 测试无返回值的异步方法
     */
    @Test
    public void test1(){
        for (int i = 0; i < 100 ; i++) {
            asyncComponent.print();
        }
    }


    /**
     * 测试有返回值的异步方法
     */
    @Test
    public void test2() throws ExecutionException, InterruptedException {
        Future<Integer> future = asyncComponent.asyncSquare(23);

        while (true){
            if(future.isCancelled()){
                log.info("异步方法已经被取消!");
                break;
            }
            if (future.isDone()){
                log.info("异步方法已经执行完毕,执行结果为:" + future.get());
                break;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值