java的异步执行方式 - @EnableAsync和@Async注解

异步调用的常用三种方式

异步调用是什么:

        简单来说,在开发流程中,如果我们从请求发起到数据返回结束,全程从开始到结束是需要等待的,没有其他的额外操作,这个过程可以称之为同步执行过程,在线程角度上,这一个请求任务,是一个单线程任务。

        那么异步调用,则是基于这个单线程情况下, 额外增加线程(多线程)进行任务处理。

        一般来说,常用的异步调用方式可以分为以下几种。

1、新建多线程

        可以直接在你需要异步执行任务的代码处,手动建立新线程(例如new Thread、Executor线程池等方式)。摘抄一个代码:下面这个是线程池的方式(线程池与多线程如何使用可以参考其他文章)

 /**
         * 定义一个线程池
         * 核心线程数(corePoolSize):1
         * 最大线程数(maximumPoolSize): 1
         * 保持连接时间(keepAliveTime):50000
         * 时间单位 (TimeUnit):TimeUnit.MILLISECONDS(毫秒)
         * 阻塞队列 new LinkedBlockingQueue<Runnable>()
         */
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1,5,50000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
        // 执行业务逻辑方法serviceTest()
        executor.execute(new Runnable() {
            @Override
            public void run() {
                asyncService.serviceTest();
            }

2、通过配置task

        java中,还可以通过配置task至xml中(类似定时任务),在指定的请开启用task,这类方式也是异步调用,但是如果当前情况是,在某一个请求中需要立刻执行异步的话,写入task执行与写入多线程执行的效果就差不多了,代码会比较冗余!

        task如何使用这个可以自行百度,不是本次需要描述的重点。       

3、通过spring提供的@EnableAsync和@Async注解

        那么上面描述的多线程建立的方式,缺点都是:

        -- 代码量其实还是较多,如果在项目中存在多个异步方法,那么这种写法会导致很冗余,所以spring提供了一个注解式解决方案。就是Async系列的注解。

        使用注解实现异步调用,需要注意2个逻辑步骤:

        1)项目中加入@EnableAsync注解

        @EnableAsync注解可以放在项目启动类或配置类上(spring boot的主启动类就可以这样使用),这表示当前项目环境支持spring异步启用。

        

package com.pld.assetpro;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableAsync
@Slf4j
public class PldAssetProApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext application = SpringApplication.run(PldAssetProApplication.class, args);

        Environment env = application.getEnvironment();
        ...

    }

}

        2)加入@Async注解

        @Async注解可以放置于类上,会表示该类下的所有方法都会是异步的,也可以放置于指定方法上,该方法被调用时会异步执行。

       例如:

@Service
@Slf4j
@Async
public class TestForJpaServiceImpl implements ITestForJpaService {
    @Override
    public void getAsyncMsg() {
        log.info("启用异步线程执行方法");
        for (int i = 0; i < 100; i++) {
            if(i%10 == 0){
                System.out.println();
            }
            System.out.print(i+" ");
        }
        System.out.println();
    }
}

       整体代码 -- 

        接口:

package com.pld.assetpro.estate.service;

import org.springframework.scheduling.annotation.Async;

/* 测试下@async和jpa */
public interface ITestForJpaService {

    void getAsyncMsg();

}

        controller:

        

package com.pld.assetpro.estate.controller;

import com.pld.assetpro.estate.service.ITestForJpaService;
import com.pld.common.util.MsgResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
@Api(value = "个人自定义测试", tags = {"控制层简单测试"})
@RequestMapping("/testCon/")
public class TestControllerForJpa {

    @Autowired
    private ITestForJpaService service;

    @PostMapping("getMsg")
    @ApiOperation(value = "test-jpa获取返回值", notes = "getMsg测试")
    public MsgResult<String> getMsg(){
        log.info("这是getMsg方法 ------------------ ");
        service.getAsyncMsg();
        log.info("getMsg方法执行完成");
        return MsgResult.successStatic("成功");
    }
}

        测试结果:可以看到getMsg方法被执行完成后,异步线程执行了service的方法(启用了多线程)。

        

        异步失效情况注意:

        通过这类注解执行异步调用,其实底层是通过生成代理对象去操作了多线程(底层就是多线程原理,运用了Executors),所以对应的,会存在一些失效情况(例如同类中,没有加@Async的方法调用了需要异步执行的@Async方法),这类失效情况与@Transactions基本雷同,可以理解为只要被调用对象的代理对象失效,那么方法执行就会变成单线程。

4、MQ

        消息队列这里不展开描述,说一下原因。

        如果面对高并发等状况,其实上面的异步调用类型中,始终是在同一个服务器下,对请求进行处理,只是开多了线程处理而已,但是还是依旧会占用服务器资源,所以不适用于高并发情况,此时我们可能就需要使用到消息队列等方案去应对了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值