zoukankan      html  css  js  c++  java
  • @Async失效之谜

    @Async如何使用

    • 异步的方法上加上@Async异步注解
    • 启动类中需要加上@EnableAsync才有效
      使用时类似于下列函数:
    new Thread(()-> System.out.println("hello world !"))
    

    @Async线程池

    • 默认线程池
      无论重复多少次,都默认8个左右的线程在跑
      异步线程:task-1执行成功
      异步线程:task-2执行成功
      异步线程:task-3执行成功
      异步线程:task-4执行成功
      异步线程:task-5执行成功
      异步线程:task-6执行成功
      异步线程:task-7执行成功
      异步线程:task-1执行成功
      异步线程:task-2执行成功
      异步线程:task-8执行成功
      异步线程:task-3执行成功
      异步线程:task-8执行成功
      异步线程:task-6执行成功
      异步线程:task-8执行成功
      异步线程:task-5执行成功
      异步线程:task-3执行成功
      异步线程:task-2执行成功
      异步线程:task-1执行成功
    • 自定义线程池配置
    /**
     * 为Async配置自定义线程池
     * 可存放的最多线程数为:MAX_POOL_SIZE+QUEUE_CAPACITY,同时进入线程池的数量超过这个就会报错
     * 线程名称最多为MAX_POOL_SIZE个
     */
    @Configuration
    public class MyTaskExecutorConfig implements AsyncConfigurer {
    
        /**
         * 设置ThreadPoolExecutor的核心池大小。
         */
        private static final int CORE_POOL_SIZE = 2;
        /**
         * 设置ThreadPoolExecutor的最大池大小。
         */
        private static final int MAX_POOL_SIZE = 3;
        /**
         * 设置ThreadPoolExecutor的BlockingQueue的容量。
         */
        private static final int QUEUE_CAPACITY = 5;
    
        /**
         * 配置类实现AsyncConfigurer接口并重写getAsyncExcutor方法,并返回一个ThreadPoolTaskExevutor
         * 这样我们就获得了一个基于线程池的TaskExecutor
         */
        @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
            taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
            taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
            taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
            taskExecutor.initialize();
            return taskExecutor;
        }
    }
    

    异步线程:ThreadPoolTaskExecutor-2执行成功
    异步线程:ThreadPoolTaskExecutor-1执行成功
    异步线程:ThreadPoolTaskExecutor-3执行成功
    异步线程:ThreadPoolTaskExecutor-1执行成功
    异步线程:ThreadPoolTaskExecutor-3执行成功
    异步线程:ThreadPoolTaskExecutor-2执行成功
    异步线程:ThreadPoolTaskExecutor-1执行成功
    异步线程:ThreadPoolTaskExecutor-3执行成功

    @Async和@Controller同时使用存在异常

    AbstractHandlerMethodMapping初始bean时,在afterPropertiesSet方法中initHandlerMethods()关联我们的SpringMVCBean

    // 类型判断
    if (beanType != null && isHandler(beanType)) {
            // url处理
    	detectHandlerMethods(beanName);
    }
    
    // Controller和RequestMapping注解判断
    protected boolean isHandler(Class<?> beanType) {
    	return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
    			AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }
    

    a、@Controller不使用@Async注解时

    @RestController
    @Slf4j
    public class MemberServiceImpl1 {
    
        @GetMapping("/addUser1")
        public String addUser() {
            log.info(">>>流程1");
            log.info(">>>流程2");
            return "success";
        }
    }
    

    image.png

    b、@Controller使用@Async注解,但不继承接口时,异步失效

    @RestController
    @Slf4j
    public class MemberServiceImpl3 {
    
        @GetMapping("/addUser3")
        public String addUser() {
            log.info(">>>流程1");
            addUserLog();
            log.info(">>>流程3");
            return "success";
        }
    
        @Async()
        public String addUserLog() {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
    
            }
            log.info(">>>流程2");
            return "success";
        }
    }
    

    image.png
    异步失效

    c、@Controller使用@Async注解,同时继承接口

    @RestController
    @Slf4j
    public class MemberServiceImpl4 implements MemberService {
    
        @Override
        @GetMapping("/addUser4")
        public String addUser() {
            log.info(">>>流程1");
            addUserLog();
            log.info(">>>流程3");
            return "success";
        }
    
        @Async()
        public String addUserLog() {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
    
            }
            log.info(">>>流程2");
            return "success";
        }
    }
    

    image.png
    访问404

    @Async使用建议

    • a、异步执行的建议单独开启一个类实现,或者从容器中直接获取到该代理类后执行
    /** 
    * 异步代码写到别的地方,不要和Controller注解同时使用
    */
    @RestController
    @Slf4j
    public class ResolveServiceImpl {
    
        @Autowired
        private MemberServiceManage memberServiceManage;
    
        @GetMapping("/resolve2")
        public String addUser() {
            log.info(">>>流程1");
            memberServiceManage.addUserLog();
            log.info(">>>流程3");
            return "success";
        }
    }
    @Component
    @Slf4j
    public class MemberServiceManage {
        @Async
        public String addUserLog() {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
    
            }
            log.info(">>>流程2");
            return "success";
        }
    }
    
    /** 
    * 使用SpringUtils获得bean后调用,不要使用this操作
    */
    @RestController
    @Slf4j
    public class ResolveServiceImpl {
    
        @GetMapping("/resolve1")
        public String addUser() {
            log.info(">>>流程1");
            //把直接调用改为从容器中取一次
            ResolveServiceImpl bean = SpringUtils.getBean(ResolveServiceImpl.class);
            bean.addUserLog();
            log.info(">>>流程3");
            return "success";
        }
    
        @Async()
        public String addUserLog() {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
    
            }
            log.info(">>>流程2");
            return "success";
        }
    }
    
    • b、异步的方法上不要加static,加了static就不走AOP了
  • 相关阅读:
    BUUCTF-RE-frimware
    BUUCTF-RE-pyre
    BUUCTF-RE-红帽2019easyRE
    BUUCTF-RE-Youngter-drive
    BUUCTF-RE-LuckGuy
    BUUCTF-RE-简单注册器
    BUUCTF-RE-8086
    BUUCTF-RE-CrackRTF
    PWN学习 ---- pwnable ----input
    linux 远程文件传输
  • 原文地址:https://www.cnblogs.com/jarye/p/13962045.html
Copyright © 2011-2022 走看看