首页 > 其他分享 >SpringBoot中@Async异步的使用及异步与同步的区别

SpringBoot中@Async异步的使用及异步与同步的区别

时间:2022-12-06 15:23:56浏览次数:36  
标签:info 异步 log test1 Async public SpringBoot

简介

在开发过程中,异步是提升系统并发能力的一个重要利器。而 spring 中的 @Async 异步注解,使我们能够非常方便地实现方法地异步调用。接下来主要结合以下几个问题来讲述 java 程序中的异步的使用:

  • 什么是同步
  • 什么是异步,以及异步的作用
  • 如何在 SpringBoot 中使用异步

1、什么是同步

同步调用,是遵循的顺序处理,一个一个调用

特征:在调用多个方法的时候,强调先后顺序,执行完一个方法再执行下一个方法,方法与方法之间不可调换先后顺序,不会并行执行

示例:

package com.example.demo.test1;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.concurrent.Future;

@Component
@Slf4j
public class SyncDemo {

    public void test1() throws Exception {
        log.info("test1开始执行");
        Long start = System.currentTimeMillis();
        Thread.sleep(1000);
        Long end = System.currentTimeMillis();
        log.info("test1执行结束");
        log.info("test1执行时长:{}毫秒", end-start);
    }

    public void test2() throws Exception {
        log.info("test2开始执行");
        Long start = System.currentTimeMillis();
        Thread.sleep(1500);
        Long end = System.currentTimeMillis();
        log.info("test2执行结束");
        log.info("test2执行时长:{}毫秒", end-start);
    }

    public void test3() throws Exception {
        log.info("test3开始执行");
        Long start = System.currentTimeMillis();
        Thread.sleep(2000);
        Long end = System.currentTimeMillis();
        log.info("test3执行结束");
        log.info("test3执行时长:{}毫秒", end-start);
    }

    public static void main(String[] args) throws Exception {
        SyncDemo syncDemo = new SyncDemo();
        Long start = System.currentTimeMillis();
        syncDemo.test1();
        syncDemo.test2();
        syncDemo.test3();
        Long end = System.currentTimeMillis();
        log.info("总执行时长:{}毫秒", end-start);
    }

}

执行结果:

总执行时长,是test1(),test2(),test3() 三个方法的近似总和

2、什么是异步

异步主要是调用方法后,不用等方法执行完毕就直接返回。异步方法会与其他方法并行执行,以此来节约时间,提高程序的并发能力。

示例:

为准确统计所有异步方法执行时间,现在将方法的返回对象,改为 Future,以此来可以判断方法是否执行完毕

示例代码如下:

IAsyncDemoService.java

package com.example.demo.test1;

import java.util.concurrent.Future;

public interface IAsyncDemoService {

    public Future<String> test1()  throws Exception ;

    public Future<String> test2()  throws Exception ;

    public Future<String> test3()  throws Exception ;

}

AsyncDemoServiceImpl.java

package com.example.demo.test1;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import java.util.concurrent.Future;

@Service
@Slf4j
public class AsyncDemoServiceImpl implements IAsyncDemoService {

    @Async
    @Override
    public Future<String> test1() throws Exception {
        log.info("test1开始执行");
        Long start = System.currentTimeMillis();
        Thread.sleep(1000);
        Long end = System.currentTimeMillis();
        log.info("test1执行结束");
        log.info("test1执行时长:{}毫秒", end-start);
        return new AsyncResult<>("test1完成");
    }

    @Async
    @Override
    public Future<String> test2() throws Exception {
        log.info("test2开始执行");
        Long start = System.currentTimeMillis();
        Thread.sleep(1500);
        Long end = System.currentTimeMillis();
        log.info("test2执行结束");
        log.info("test2执行时长:{}毫秒", end-start);
        return new AsyncResult<>("test2完成");
    }

    @Async
    @Override
    public Future<String> test3() throws Exception {
        log.info("test3开始执行");
        Long start = System.currentTimeMillis();
        Thread.sleep(2000);
        Long end = System.currentTimeMillis();
        log.info("test3执行结束");
        log.info("test3执行时长:{}毫秒", end-start);
        return new AsyncResult<>("test3完成");
    }
}

DemoApplicationTests.java

package com.example.demo;

import com.example.demo.test1.IAsyncDemoService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.concurrent.Future;

@SpringBootTest
@Slf4j
class DemoApplicationTests {

    @Autowired
    IAsyncDemoService asyncDemoService;

    @Test
    void contextLoads() throws Exception{
        Long start = System.currentTimeMillis();
        Future task1 = asyncDemoService.test1();
        Future task2 = asyncDemoService.test2();
        Future task3 = asyncDemoService.test3();

        while (true) {
            if (task1.isDone() && task2.isDone() && task3.isDone()) {
                break;
            }
        }
        Long end = System.currentTimeMillis();
        log.info("总执行时长:{}毫秒", end-start);
    }

}

执行结果如下:总执行时间与执行最长的 test3()方法的时间相近

结论:异步方法是通过形式,调用后即返回,具体方法的执行,不影响其他方法的执行,多个方法并行的方式实现。

3、@Async 失效的情况

在使用 注解@Async 的时候,一定要注意规避以下情况,会造成 注解失效的情况

  • 注解@Async的方法不是public方法

  • 注解@Async的返回值只能为void或Future

  • 注解@Async方法使用static修饰也会失效

  • spring无法扫描到异步类,没加注解@Async或@EnableAsync注解

  • 调用方与被调用方不能在同一个类

  • 类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象

  • 在Async方法上标注@Transactional是没用的.但在Async方法调用的方法上标注@Transcational是有效的

4、异步线程池的设置

使用 @Async 来实现异步,默认使用Spring创建ThreadPoolTaskExecutor,默认线程池的参数设置为:

  • 默认心线程数:8,

  • 最大线程数:Integet.MAX_VALUE,

  • 队列使用LinkedBlockingQueue,

  • 容量是:Integet.MAX_VALUE,

  • 空闲线程保留时间:60s,

  • 线程池拒绝策略:AbortPolicy。

问题:_
_并发情况下,会无限创建线程,导致系统资源耗尽,所以我们要手动设置线程池的配置,来避免无限创建线程的情况。

配置如下:
application.yaml

spring:
  task:
    execution:
      pool:
        max-size: 6
        core-size: 3
        keep-alive: 3s
        queue-capacity: 1000

自定义线程池配置类:

ExecutorConfig.java

@Configuration
@Data
public class ExecutorConfig{

    /**
     * 核心线程
     */
    private int corePoolSize;

    /**
     * 最大线程
     */
    private int maxPoolSize;

    /**
     * 队列容量
     */
    private int queueCapacity;

    /**
     * 保持时间
     */
    private int keepAliveSeconds;

    /**
     * 名称前缀
     */
    private String preFix;

    @Bean
    public Executor myExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setThreadNamePrefix(preFix);
        executor.setRejectedExecutionHandler( new ThreadPoolExecutor.AbortPolicy());
        executor.initialize();
        return executor;
    }
}

使用方式:

在使用 @Async 的时候,指定线程池为自定义线程池 myExecutor

例如:

    @Async("myExecutor")
    public void test1() throws Exception {

    }

标签:info,异步,log,test1,Async,public,SpringBoot
From: https://www.cnblogs.com/xiangningdeguang/p/16955377.html

相关文章

  • Springboot优雅进行字段检验
    Springboot优雅进行字段检验1、ControllerVSService推荐与业务无关的放在controller层中进行校验,而与业务相关的放在service层中校验。2、常用校验工具类使用Hiberna......
  • springboot2 搭建日志收集系统存入mongodb + redis+mq+线程池+xxljobs
    我们看到了高效批量插入mongodb速度还不错,那么我们的系统日志收集怎么做呢。当然当前文件日志收集效果也不错,比如前面博文写的elkf搭建日志收集系统。但我们系统中总是有......
  • 使用AsyncTask异步加载图片
    主要看看AsyncTask如何使用:MainActivity.java1.publicclassMainActivityextendsActivity{2.privatestaticfinalStringTAG="MainActivity";3.privat......
  • springboot2 mongodb 高效批量入库--环境搭建
    当今使用微服务越来越多,每个服务都需要记录日志,那么记录到mysql中已完全不合适了。那么就记录到mongo中吧。想要速度快,那么一定要使用批量保存,做过尝试入库10万数据,逐条插......
  • SpringBoot整合Netty+WebSocket
    SpringBoot整合Netty+WebSocket构建环境pom.xml<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w......
  • SpringBoot 接口并发限制(Semaphore)
    可以使用JMeter辅助测试https://blog.csdn.net/weixin_45014379/article/details/124190381@RestController@RequestMapping({"/Test"})publicclasstest{L......
  • 对graalvm、springboot3.0一些新特性的探究
    环境:系统:IntelcoreMacVentura13.0.1工具: Idea:2022.2.3 gradle:7.4(idea自带的)  openjdk:version"17.0.5"2022-10-18 graalvm: CE22.3.0 ......
  • 使用 aop + guava 为 springboot 应用做限流
    1.引入guava依赖<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId></dependency>编写......
  • SpringBoot防止XSS
    前言:什么是XSS在跨站脚本(XSS)攻击中,攻击者可以在受害者的浏览器中执行恶意脚本。这种攻击通常是通过在网页中插入恶意代码(JavaScript)来完成的。攻击者在使用攻击后一般......
  • Springboot 系列 (20) - Springboot+ElasticSearch 实现全文搜索(二)
    在“Springboot系列(19)-Springboot+ElasticSearch实现全文搜索(一)”里我们演示了安装配置ElasticSearch和使用curl调用ElasticSearchAPI,本文将演示在Springb......