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
  }
}

目录
相关文章
|
3月前
|
Java Spring
@Async 的实现原理是什么?
【8月更文挑战第17天】@Async 的实现原理是什么?
107 3
|
缓存 Java 程序员
Spring中异步注解@Async的使用、原理及使用时可能导致的问题
本文主要介绍了Spring中异步注解的使用、原理及可能碰到的问题,针对每个问题文中也给出了方案。希望通过这篇文章能帮助你彻底掌握`@Async`注解的使用,知其然并知其所以然!
13196 4
|
缓存 Java Spring
异步编程 - 09 Spring框架中的异步执行_@Async注解异步执行原理&源码解析
异步编程 - 09 Spring框架中的异步执行_@Async注解异步执行原理&源码解析
56 0
|
Java Spring
异步编程 - 08 Spring框架中的异步执行_TaskExecutor接口和@Async应用篇2
异步编程 - 08 Spring框架中的异步执行_TaskExecutor接口和@Async应用篇2
123 0
|
XML Java 数据格式
异步编程 - 08 Spring框架中的异步执行_TaskExecutor接口和@Async应用篇
异步编程 - 08 Spring框架中的异步执行_TaskExecutor接口和@Async应用篇
76 0
|
6月前
|
Java Spring
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
139 0
|
6月前
|
监控 前端开发 JavaScript
async/await:使用同步的方式去写异步代码
async/await:使用同步的方式去写异步代码
104 1
|
安全 Java UED
SpringBoot 如何使用 @Async 注解处理异步事件
SpringBoot 如何使用 @Async 注解处理异步事件
|
Java 测试技术 Spring
@Async注解 -- 异步调用的万金油
@Async注解 -- 异步调用几乎是处理高并发Web应用性能问题的万金油.那么什么是“异步调用”?“异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。
88 1
|
前端开发
前端学习案例26-aysnc和await之2
前端学习案例26-aysnc和await之2
75 0
前端学习案例26-aysnc和await之2