springboot使用@Async实现异步调用

2022/8/22 23:23:10

本文主要是介绍springboot使用@Async实现异步调用,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

异步与同步

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

常规的异步调用处理方式

 在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使用@Async实现异步调用的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程