SQI中@Async异步注解简单使用

简介: 最近在Review代码中看到有些同学在使用多线程的时候比较随意,基本上各种使用方式都有。但是有些写法其实是适合standalone的程序,有的写法在Spring中得到了简化。所以建议大家在在SQI相关开发中可以尝试用@Async注解的方式完成异步操作,既清晰明了,也简单方便。 ## 异步的几种写法 + 刀耕火种年代 这个年代是没有线程池管理的,实现了Runnable接口后

最近在Review代码中看到有些同学在使用多线程的时候比较随意,基本上各种使用方式都有。但是有些写法其实是适合standalone的程序,有的写法在Spring中得到了简化。所以建议大家在在SQI相关开发中可以尝试用@Async注解的方式完成异步操作,既清晰明了,也简单方便。

异步的几种写法

  • 刀耕火种年代

    这个年代是没有线程池管理的,实现了Runnable接口后就start来运行。

  • 大航海时代

    这个年代已经开始使用线程池了,我们可以看一段示例代码

      ExecutorService executor = Executors.newFixedThreadPool(N);
      for (int i = 0; i < kProducts.size(); i++) {
          Products product = kProducts.get(i);
    if (pid != null || bizdate != null) {
        if (bizdate == null) {
            bizdate = "2015-04-01";
        }
    executor.execute(new offlineKeludeJob(product, DateUtils.getMorning(DateUtils.parseDate(bizdate))));
             } else {
        executor.execute(new offlineKeludeJob(product));
    }
      }
      executor.shutdown();

    这段代码在standalone程序中看起来问题不大。但是在Web服务中每个Request都会来调用一次,会使得堆积的请求处理队列消耗非常大的内存,极端情况下会引发OOM问题。

  • 工业化时代

在这里大家使用Spring中的ThreadPoolTaskExecutor,使用起来也没有特别大的问题。例如下面这个简单的例子

   <task:executor id="labelTaskExecutor" pool-size="100" queue-capacity="10000" rejection-policy="ABORT"/>
   @Autowired
   ThreadPoolTaskExecutor labelDbExecutor;
   labelTaskExecutor.submit(new Runnable() {
       @Override
       public void run() {
           try {
               Integer ret = insert(tmpLabelData);
               if (ret <= 0) {
                   logger.error(String.format("[ERRORLabelData]insert data failed! label data:%s", JSONObject.toJSONString(tmpLabelData)));
                    }
              } catch (Exception e) {
                  logger.error(String.format("[ERRORLabelData]insert data into db exception!"), e);
               }
           }
      }
   );

@Async注解使用

上面说了那么多用户,其实都没有什么用。只是用来突出关于Async注解的使用。最初的两种方法都因为自身的不足,不建议在SQI项目中直接使用。而最后一个方法虽然没有什么问题,但是写起来比较麻烦,还需要自己实现Runnable接口。那么对于我们来说,有没有更简单方便的方式来使用呢?答案就是Spring 3.0带来Async注解,其使用主要就只有两步。

  • 在applicationContext.xml中增加线程池配置

    <context:component-scan base-package="com.alibaba.search" />
    <task:annotation-driven executor="defaultExecutor"/>
    <task:executor id="defaultExecutor" pool-size="100" queue-capacity="10000" rejection-policy="ABORT"/>
  • 在你需要调用的方法上加上相应的注解

    @Service
    public class TestClass {
      @Async
      public void asyncTest() {
        //Do something
      }
    }

@Async使用注意事项

  • 类内部的方法间的调用是不起效果的,具体是在于Async是基于bean自动扫描后生成的proxy实现的。那么一定要用怎么办,最简单的办法就是拆出到另外一个class里面。
  • 如果在多个XML中进行了配置是会覆盖的。例如SQI在web.xml中定义了

    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springMvcConfig.xml</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>

那么如果同时在springMvcConfig.xml和applicationContext.xml中有对task:executor的定义的话,DispatcherServlet中加载的XML会覆盖掉ContextLoaderListener中加载的。用我们的例子来讲就是springMvcConfig.xml中的配置会覆盖掉applicationContext.xml。

  • 如果要使用多个线程池怎么办?在使用的时候指定一下对应的ID就可以了。

    <context:component-scan base-package="com.alibaba.search" />
    <task:annotation-driven executor="defaultExecutor"/>
    <task:executor id="defaultExecutor" pool-size="100" queue-capacity="10000" rejection-policy="ABORT"/>
    <task:executor id="statisticExecutor" pool-size="100" queue-capacity="10000" rejection-policy="ABORT"/>
@Service
public class TestClass {
  @Async
  public void asyncTest() {
    //Do something
  }
  @Async("statisticExecutor")
  public void statisticAsyncTest() {
    //Do some statistic
  }
}

目录
相关文章
|
7月前
|
Java
springboot异步操作之Async
springboot异步操作之Async
124 1
|
25天前
|
Java Spring
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
24 0
|
缓存 Java 程序员
Spring中异步注解@Async的使用、原理及使用时可能导致的问题
本文主要介绍了Spring中异步注解的使用、原理及可能碰到的问题,针对每个问题文中也给出了方案。希望通过这篇文章能帮助你彻底掌握`@Async`注解的使用,知其然并知其所以然!
11606 4
|
6月前
|
缓存 Java Spring
异步编程 - 09 Spring框架中的异步执行_@Async注解异步执行原理&源码解析
异步编程 - 09 Spring框架中的异步执行_@Async注解异步执行原理&源码解析
34 0
|
6月前
|
XML Java 数据格式
异步编程 - 08 Spring框架中的异步执行_TaskExecutor接口和@Async应用篇
异步编程 - 08 Spring框架中的异步执行_TaskExecutor接口和@Async应用篇
44 0
|
6月前
|
Java Spring
异步编程 - 08 Spring框架中的异步执行_TaskExecutor接口和@Async应用篇2
异步编程 - 08 Spring框架中的异步执行_TaskExecutor接口和@Async应用篇2
61 0
|
7月前
|
安全 Java UED
SpringBoot 如何使用 @Async 注解处理异步事件
SpringBoot 如何使用 @Async 注解处理异步事件
|
8月前
|
前端开发 Java 测试技术
SpringBoot-27- @Async实现异步调用 什么是异步调用
异步调用是相对于同步调用的,同步调用是按照顺序进行执行任务,只有上一个任务执行完成下一个任务才能执行,异步调用是指在按照顺序执行任务的过程中不需要等待任务结果的出现,就可以顺序执行下一个任务。
61 0
|
10月前
|
XML IDE Java
JAVA多线程以及Spring异步注解@Async
JAVA多线程以及Spring异步注解@Async
408 1
|
11月前
|
Java 测试技术 Spring
@Async注解 -- 异步调用的万金油
@Async注解 -- 异步调用几乎是处理高并发Web应用性能问题的万金油.那么什么是“异步调用”?“异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。
61 1