方法异步

org.springframework.scheduling.annotation.Async
@Async注解方法, 在子线程中异步执行

https://www.baeldung.com/spring-async

spring @Async 没作用

失效原因
1.没有在@SpringBootApplication启动类当中添加注解@EnableAsync注解。
2.异步方法使用注解@Async的返回值只能为void或者Future。
3.没有走Spring的代理类。因为@Transactional和@Async注解的实现都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器。

解决方法:
这里具体说一下第三种情况的解决方法。
1.注解的方法必须是public方法。
2.方法一定要从另一个类中调用,也就是从类的外部调用,类的内部调用是无效的。
3.如果需要从类的内部调用,需要先获取其代理类,下面上代码

@Service
public class SpringAsyncServiceImpl {


  public void entry() {

      System.out.println("entry thread name # " + Thread.currentThread().getName());

      SpringAsyncServiceImpl asyncService = SpringUtils.getBean(SpringAsyncServiceImpl.class);
      asyncService.voidMethod();
  }

  @Async
  public void voidMethod() {
      System.out.println(" thread name  # " + Thread.currentThread().getName());
  }


}

本类中可以定义实现本类中调用的本类的异步多线程方法;
必须实现的两种:
public方法
手动获取spring bean

@Component("springContextUtil")
public class SpringUtils implements ApplicationContextAware {


    private static ApplicationContext applicationContext = null;

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @SuppressWarnings("unchecked")
    public static  T getBean(String beanId) {
        return (T) applicationContext.getBean(beanId);
    }

    public static  T getBean(Class requiredType) {
        return (T) applicationContext.getBean(requiredType);
    }
    /**
     * Spring容器启动后,会把 applicationContext 给自动注入进来,然后我们把 applicationContext
     *  赋值到静态变量中,方便后续拿到容器对象
     * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
     */
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }
}

子线程抛出异常, 对调用线程的影响

@Service
public class SpringAsyncServiceImpl {


    public void entry() throws ExecutionException, InterruptedException {

        System.out.println("entry thread name # " + Thread.currentThread().getName());

        SpringAsyncServiceImpl asyncService = SpringUtils.getBean(SpringAsyncServiceImpl.class);
//        asyncService.voidMethod();
        Future aFuture = asyncService.fuyureReturn();

        System.out.println("entry end");

        System.out.println(aFuture.get());
    }

    @Async
    public void voidMethod() {
        System.out.println(" thread name  # " + Thread.currentThread().getName());
//        int i = 10 / 0;
    }

    @Async
    public Future fuyureReturn() {

        FutureTask futureTask = new FutureTask<>(() -> {

            Thread.sleep(1000L);

//            int i = 10 / 0;


            return Thread.currentThread().getName() + " # 我沉睡了1000ms 现在我醒来了";

        });

        futureTask.run();


        return futureTask;
    }

}

子线程抛出异常, 当异步方法返回void,则异常不会被传播到调用线程。

子线程抛出异常, 当异步线程返回Future对象, 且在调用线程中执行future.get(), 则调用线程也会抛出异常。

image.png

你可能感兴趣的:(方法异步)