首页 > 其他分享 >springboot使用@Async实现异步调用

springboot使用@Async实现异步调用

时间:2022-08-22 19:57:10浏览次数:190  
标签:异步 springboot org long 线程 import Async public

异步与同步

 同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果。 
 异步调用则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕;而是继续执行下面的流程。

常规的异步调用处理方式

 在Java中,一般在处理类似的场景之时,都是基于创建独立的线程去完成相应的异步调用逻辑,
 通过主线程和不同的线程之间的执行流程,从而在启动独立的线程之后,主线程继续执行而不会产生停滞等待的情况。

Spring中的@Async

 在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,
 将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。

分析

在spring中,通过任务执行器,也就是TaskExecutor来实现多线程和并发编程。
使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。 
而实际开发中任务一般是非阻碍的,也就是非异步的,所以我们要在配置类中通过@EnableAsync开启对异步任务的支持,
并通过在实际执行的Bean的方法中使用@Async注解来声明其是一个异步任务。	 

配置任务执行器

/**
 * 通过重写getAsyncExecutor方法,制定默认的任务执行由该方法产生
 * 
 * 配置类实现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;
}
 

一、configuration包下的配置类,实现AsyncConfigurer接口

package com.liu.configuration;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * 利用@EnableAsync注解开启异步任务支持
 */
@Configuration
@EnableAsync
public class TaskExecutorConfig implements AsyncConfigurer {

    /**
     * Set the ThreadPoolExecutor's core pool size.
     */
    private static final int CORE_POOL_SIZE = 5;

    /**
     * Set the ThreadPoolExecutor's maximum pool size.
     */
    private static final int MAX_POOL_SIZE = 20;

    /**
     * Set the capacity for the ThreadPoolExecutor's BlockingQueue.
     */
    private static final int QUEUE_CAPACITY = 10;

    /**
     * 通过重写getAsyncExecutor方法,制定默认的任务执行由该方法产生
     * 
     * 配置类实现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;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return null;
    }

    /**
     * 自定义任务执行器:在定义了多个任务执行器的情况下,可以使用@Async("getMineAsync")来设定
     * 
     * @return
     */
    @Bean
    public Executor getMineAsync() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(CORE_POOL_SIZE - 4);
        executor.setMaxPoolSize(MAX_POOL_SIZE - 10);
        executor.setQueueCapacity(QUEUE_CAPACITY - 5);
        executor.setThreadNamePrefix("mineAsync-");
        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

}

二、业务层

package com.liu.service;

import java.util.concurrent.Future;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

/**
 * 操作计算 service 类:简单实现有关异步和同步两种计算方式的性能比较
 */
@Component
public class ArithmeticService {

    private final static Logger logger = LoggerFactory.getLogger(ArithmeticService.class);

    public static final int DoTime = 5000;

    /**
     * 异步任务 只需要在所需实现异步的方法上加上@Async注解, 并通过Future<T>来接受异步方法的处理结果
     * 通过@Async注解表明该方法是个异步方法,如果注解在类级别,则表明该类所有的方法都是异步方法
     * 
     * @return
     */
    @Async
    public Future<Long> subByAsync() throws Exception {
        long start = System.currentTimeMillis();
        long sum = 0;
        Thread.sleep(DoTime);
        long end = System.currentTimeMillis();
        sum = end - start;
        logger.info("\t 完成任务一");
        return new AsyncResult<>(sum);
    }

    /**
     * 仅使用异步注解的方式实现异步方法
     * 
     * @return
     */
    @Async
    public void subByVoid() throws Exception {
        long start = System.currentTimeMillis();
        long sum = 0;
        Thread.sleep(DoTime);
        long end = System.currentTimeMillis();
        sum = end - start;
        logger.info("\t 完成任务二   ");
        logger.info("注解任务执行的时间是: " + sum + "(毫秒)");
    }

    /**
     * 使用同步计算的方式--同步调用
     * 
     * @return
     */
    public long subBySync() throws Exception {
        long start = System.currentTimeMillis();
        long sum = 0;
        Thread.sleep(DoTime);
        long end = System.currentTimeMillis();
        sum = end - start;
        logger.info("\t 完成任务三   ");
        return sum;
    }

    @Async("getMineAsync")
    public void doMineAsync(int i) throws Exception {
        System.out.println("------\t:" + i);
        Thread.sleep(10000);
    }
}

 

三、controller层代码

package com.liu.controller;

import java.util.concurrent.Future;

import com.liu.service.ArithmeticService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/async")
public class IndexController {

    private final static Logger logger = LoggerFactory.getLogger(IndexController.class);

    @Autowired
    private ArithmeticService arithmeticService;

    @GetMapping("/test1")
    public void index() {
        long start = System.currentTimeMillis();
        try {
            logger.info("--------------------------------------------\n");
            logger.info("每个任务执行的时间是:" + arithmeticService.DoTime + "(毫秒)");

            Future<Long> task = arithmeticService.subByAsync();

            arithmeticService.subByVoid();

            long sync = arithmeticService.subBySync();

            while (true) {
                if (task.isDone()) {
                    long async = task.get();
                    logger.info("异步任务执行的时间是:" + async + "(毫秒)");
                    // logger.info("注解任务执行的时间是: -- (毫秒)");
                    logger.info("同步任务执行的时间是:" + sync + "(毫秒)");
                    break;
                }
            }
            logger.info("--------------------------------------------\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        logger.info("\t........请求响应时间为:" + (end - start) + "(毫秒)");
    }

    /**
     * 自定义实现线程异步
     */
    @GetMapping("/test2")
    public void mineAsync() {
        for (int i = 0; i < 100; i++) {
            try {
                arithmeticService.doMineAsync(i);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

 


标签:异步,springboot,org,long,线程,import,Async,public
From: https://www.cnblogs.com/l-926/p/16614035.html

相关文章

  • 3.springboot和springcloud alibaba版本问题
    启动项目报错Causedby:java.lang.ClassNotFoundException:...boot.context.properties.ConfigurationPropertiesBean 解决办法:我的springboot用的<parent>......
  • java springboot 初体验 (七)对接链路追踪
    上一篇javaspringboot初体验(六)添加统一的入参出参打印日志(使用切面)https://www.cnblogs.com/zwjvzwj/p/16612094.htmlMDC介绍MDC(MappedDiagnosticContext,映射......
  • SpringBoot中的事务
    [转]https://www.cnblogs.com/l-liu/p/16169399.html 一、说明介绍①使用事务,我们只需要在需要事务的类或方法上使用@Transactional注解即可,当注解在类上的时候意味着此......
  • java springboot 初体验 (六)添加统一的入参出参打印日志(使用切面)
    上一篇javaspringboot初体验(五)对接apollohttps://www.cnblogs.com/zwjvzwj/p/16602858.htmlpom文件中添加依赖<!--切面--><dependency>......
  • springboot+license
    原文:https://www.zifangsky.cn/1277.htmlLicense,即版权许可证,一般用于收费软件给付费用户提供的访问许可证明。根据应用部署位置的不同,一般可以分为以下两种情况讨论:应用......
  • springboot + paypal
    原文:https://www.cnblogs.com/rickzhai/p/7924181.html做全球性的支付,选用paypal!为什么选择paypal?因为paypal是目前全球最大的在线支付工具,就像国内的支付宝一样,是一个基......
  • SpringBoot读取.yml配置文件最常见的两种方式-源码及其在nacos的应用
    一、前言我们在开发中会经常遇到一些可能会变的值,比如数据库的密码,一些关键链接的配置等等。都需要我们写在配置文件中,这样可以把这些配置文件放到nacos上进行管理,修改na......
  • 10.异步mysql
    python中操作mysql连接、操作、断开都是网络IO#安装支持异步aiomysql的模块pip3installaiomysqlasyncdefexecute():#网络IO操作,连接数据库,遇到IO切换任务......
  • 2022.8.21 Forkjoin与异步回调
    14、Forkjoin(分支合并)什么是ForkJoinForkJoin在JDK1.7, 并行执行任务!提高效率。在大数据量中!大数据:MapReduce(把大任务拆分为小任务)Forkjoin特点:工作窃取,这里......
  • 蚂蚁金服开源的这份SpringBoot笔记,曾在24小时内GitHub星标48k
    前言Spring的影响力想必就不用小编多说了,今天要跟大家说的是SpringBoot。SpringBoot作为目前Spring技术体系中炙手可热的框架之一,已经是开发者们的必备神器了。在实际......