SpringBoot4.0新特性Resilience之并发限制详解

 更新时间:2026年01月30日 10:48:28   作者:若鱼1919  
本文给大家介绍SpringBoot4.0新特性Resilience之并发限制的相关知识,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

文章末尾我们讲了失败重试的相关知识,下面我们来看另一个新特性 - @ConcurrencyLimit并发限制,简单的说,它可以限制方法的并发访问数。

使用入门

@ConcurrencyLimit@Retryable类似,可以加在单个方法上,设置方法级别的并发限制,也可以加在类上,给类中所有的通过代理调用的方法统一设置并发限制,使用起来非常简单,仅需2步:

  • 在启动类添加@EnableResilientMethods
@EnableResilientMethods
@SpringBootApplication
public class Springboot4Application {}
  • 在业务类或者方法上添加@ConcurrencyLimit
@ConcurrencyLimit(limit = 1)
@GetMapping(path = "/demo")
public String demo(){
    log.info("ConcurrencyLimitController demo");
    return "demo";
}
  • limit = 1:说明本方法同时只允许1个并发访问,如果有多余的并发请求会一直阻塞等待。
  • 加在controller的方法上等于实现了一个简易版的限流功能,可以对接口做一定程度的保护。

测试一下效果:

public static void main(String[] args) throws Exception{
    System.out.println("start at " + LocalDateTime.now());
    int threadCount = 5;
    CountDownLatch start = new CountDownLatch(1);
    CountDownLatch stop = new CountDownLatch(threadCount);
    for(int i=0; i<threadCount; i++){
        new Thread(()->{
            try {
                start.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            String res = new RestTemplate().getForObject("http://localhost:8080/api/concurrency-limit/demo", String.class);
            System.out.println(res);
            stop.countDown();
        }).start();
    }
    start.countDown();
    stop.await();
    System.out.println("end at " + LocalDateTime.now());
}

我们使用5个线程并发访问前面的接口,因为接口只允许1个并发,因此总执行时长会超过5秒钟,日志如下:

2026-01-23T12:52:43  INFO 11868 --- [nio-exec-4] c.g.x.s.c.ConcurrencyLimitController     : ConcurrencyLimitController demo
2026-01-23T12:52:44  INFO 11868 --- [nio-exec-2] c.g.x.s.c.ConcurrencyLimitController     : ConcurrencyLimitController demo
2026-01-23T12:52:45  INFO 11868 --- [nio-exec-5] c.g.x.s.c.ConcurrencyLimitController     : ConcurrencyLimitController demo
2026-01-23T12:52:46  INFO 11868 --- [nio-exec-3] c.g.x.s.c.ConcurrencyLimitController     : ConcurrencyLimitController demo
2026-01-23T12:52:47  INFO 11868 --- [nio-exec-1] c.g.x.s.c.ConcurrencyLimitController     : ConcurrencyLimitController demo

实现原理

@ConcurrencyLimit背后是ConcurrencyThrottleSupport, 因此我们也可以用编程的方式手动的来做并发控制,比如我们可以利用现成的SyncTaskExecutor来实现与前面相同的并发限制功能:

SyncTaskExecutor taskExecutor = new SyncTaskExecutor(){
    {
        // 设置并发数
        this.setConcurrencyLimit(1);
    }
};
@GetMapping(path = "/demo2")
public String demo2()throws Exception{
    return taskExecutor.execute(()->{
        log.info("ConcurrencyLimitController demo2");
        Thread.sleep(1000);
        return "demo";
    });
}

更多SpringBoot4.0的知识请参考:https://www.jb51.net/database/350507r03.htm

补充:SpringBoot4.0新特性-Resilience之失败重试

从Spring7.0版本开始,Spring Framework核心模块已经集成了常用Resilience相关功能,主要包括了对方法调用的失败重试支持以及并发控制支持。SpringBoot 4.0默认的Spring的版本就是Spring 7.0, 因此SpringBoot 4.0自然也就具有了这些特性。本文先来学习下失败重试,下一篇再来学习并发控制。

注解式失败重试@Retryable

@Retryable 注解可以加在单个方法上,设置方法级别的重试,也可以加在类上,给类中所有的通过代理调用的方法统一指定重试特性,使用起来非常简单,仅需2步:

  • 在启动类添加@EnableResilientMethods
@EnableResilientMethods</code><code>@SpringBootApplication</code><code>public class Springboot4Application {}
  • 在业务类或者方法上添加@Retryable
@Retryable</code><code>@GetMapping(path = "/demo")</code><code>public String demo(){</code><code>    log.info("RetryController demo");</code><code>    int a = 1/0;</code><code>    return "demo";</code><code>}

默认情况下,当方法调用抛出任何异常时都将触发重试,初始失败后最多进行 3 次重试尝试(maxRetries = 3),且每次重试之间间隔 1 秒延迟。因此,如果业务方法一直失败的话,最多会被调用1(初始调用)+ 3(最多重试)=4次。

自定义重试次数和间隔

@Retryable包含以下属性可以用来设置重试的次数和间隔:

  • maxRetries:最大重试次数,不包含初始调用
  • maxDelay:这是任何重试尝试的最大延迟时长,用于限制 jitter() 和 multiplier() 机制可能增加的延迟上限。
  • delay:初次调用失败后的基础延迟时长。若指定了延迟倍数,此值将作为初始延迟基数进行倍增计算。
  • multiplier:用于计算下一次重试延迟的倍数,该倍数将应用于前一次的延迟时间(起始值为 delay() 设置的基础延迟)以及每次重试所适用的抖动时间。
  • jitter:基础重试尝试的抖动值,会以随机加减的方式作用于计算出的延迟时间,从而产生一个介于 delay - jitter 到 delay + jitter 之间的值,但该值永远不会低于基础 delay() 或高于 maxDelay()。如果指定了延迟倍数,抖动值也将按此倍数进行缩放。

举个例子说明一下:

@Retryable(
        maxRetries = 3,
        delay = 1000,
        maxDelay = 5000,
        multiplier = 3,
        jitter = 100
)

日志如下:​​​​​​​

2026-01-22T15:37:13  INFO -- [8080-exec-1] RetryController    : RetryController demo
2026-01-22T15:37:14  INFO -- [8080-exec-1] RetryController    : RetryController demo
2026-01-22T15:37:17  INFO -- [8080-exec-1] RetryController    : RetryController demo
2026-01-22T15:37:22  INFO -- [8080-exec-1] RetryController    : RetryController demo
2026-01-22T15:37:22 ERROR -- [8080-exec-1] [dispatcherServlet]: Servlet.service() for...

13秒初次调用,delay1秒以后,14秒发起第一次重试,重试失败,发起第二次重试,需要延迟multiplier 3* delay1 = 3秒,此时的delay就变成了3秒,因此17秒发起第二次重试,还是失败,需要延迟multiplier(3) * delay(3)= 9秒,但是maxDelay是5秒,因此实际重试发生在17+5=22秒。重试次数耗尽还是失败,最后抛出异常。在此过程中,请求会一直阻塞,直到抛出异常,总耗时超过8秒。

自定义触发重试的异常类型

默认情况下,任何类型的异常都会触发重试,可以通过以下属性来限定需触发重试的异常类型。

  • includes:用于指定应触发重试的异常类型。
  • excludes:用于指定不应触发重试的异常类型,优先级更高。
  • predicate:自定义MethodRetryPredicate, 优先级最低。

比如下面的案例将不会触发重试:​​​​​​​

@Retryable(
    includes = RuntimeException.class,
    excludes = ArithmeticException.class
)
@GetMapping(path = "/demo")
public String demo(){
    log.info("RetryController demo");
    int a = 1/0;
    return "demo";
}

编程式失败重试RetryTemplate

与 @Retryable不同,RetryTemplate 提供了一组API,可用于对任意代码块进行重试操作。当然此时就不再需要@EnableResilientMethods注解了,比如:​​​​​​​

@GetMapping(path = "/demo2")
public String demo2() throws Exception{
    RetryTemplate retryTemplate = new RetryTemplate();
    return retryTemplate.execute(()->{
        log.info("RetryController demo2");
        int a = 1/0;
        return "demo2";
    });
}

RetryTemplate 会根据配置的 RetryPolicy 来执行并可能重试一个可重试的操作,默认的 RetryPolicy@Retryable的行为一致,当方法调用抛出任何异常时都将触发重试,初始失败后最多进行 3 次重试尝试(maxRetries = 3),且每次重试之间间隔 1 秒延迟。

自定义重试行为

可以自定义RetryPolicy对重试行为进行自定义,比如:​​​​​​​​​​​​​

@GetMapping(path = "/demo2")
public String demo2() throws Exception{
    var retryPolicy = RetryPolicy.builder()
            .maxRetries(3)
            .delay(Duration.ofMillis(1000))
            .maxDelay(Duration.ofMillis(5000))
            .multiplier(3)
            .jitter(Duration.ofMillis(100))
            .includes(RuntimeException.class)
            .excludes(ArithmeticException.class)
            .build();
    RetryTemplate retryTemplate = new RetryTemplate(retryPolicy);
    return retryTemplate.execute(()->{
        log.info("RetryController demo2");
        int a = 1/0;
        return "demo2";
    });
}

到此这篇关于SpringBoot4.0新特性Resilience之并发限制详解的文章就介绍到这了,更多相关SpringBoot Resilience并发限制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中SimpleDateFormat的使用方法

    Java中SimpleDateFormat的使用方法

    这篇文章主要为大家详细介绍了Java中SimpleDateFormat的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • SpringBoot基于线程池的订单创建并行化实践过程

    SpringBoot基于线程池的订单创建并行化实践过程

    文章介绍了电商系统订单创建接口的并行处理方案,通过分析业务流程、选择合适的线程池和技术,解决了高并发场景下的性能问题
    2025-12-12
  • 详解Java如何优雅的实现字典翻译

    详解Java如何优雅的实现字典翻译

    当我们在Java应用程序中需要对字典属性进行转换返回给前端时,如何简单、方便、并且优雅的处理是一个重要问题。在本文中,我们将介绍如何使用Java中的序列化机制来优雅地实现字典值的翻译,从而简化开发
    2023-04-04
  • Java中锁分类及在什么场景下使用

    Java中锁分类及在什么场景下使用

    文章详细介绍了锁的进阶分类,如可重入锁、乐观锁、公平锁、读写锁等,并提供了具体的代码示例,最后,文章给出了实战选型指南,帮助开发者根据具体业务场景选择合适的锁类型,以达到最优的性能和可维护性,感兴趣的朋友跟随小编一起看看吧
    2026-01-01
  • SpringBatch数据写入实现

    SpringBatch数据写入实现

    Spring Batch通过ItemWriter接口及其丰富的实现,提供了强大的数据写入能力,本文主要介绍了SpringBatch数据写入实现,具有一定的参考价值,感兴趣的可以了解一下
    2025-04-04
  • java中equals和等号(==)的区别浅谈

    java中equals和等号(==)的区别浅谈

    java中equals和等号(==)的区别浅谈,需要的朋友可以参考一下
    2013-05-05
  • Java中JUC 的 Exchange 交换器详情

    Java中JUC 的 Exchange 交换器详情

    这篇文章主要介绍了Java中JUC 的 Exchange 交换器详情,文章基于Java的相关资料展开详细的内容介绍,需要的小伙伴可以参考一下
    2022-05-05
  • Spring AI借助全局参数实现智能数据库操作与个性化待办管理

    Spring AI借助全局参数实现智能数据库操作与个性化待办管理

    这篇文章主要介绍了Spring AI借助全局参数实现智能数据库操作与个性化待办管理,本文给大家介绍的非常详细,需要的朋友可以参考下
    2024-11-11
  • Java如何实现树的同构?

    Java如何实现树的同构?

    今天给大家带来的是关于Java的相关知识,文章围绕着Java如何实现树的同构展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Java正则验证电话,手机,邮箱,日期,金额的方法示例

    Java正则验证电话,手机,邮箱,日期,金额的方法示例

    这篇文章主要介绍了Java正则验证电话,手机,邮箱,日期,金额的方法,结合具体实例形式分析了Java针对电话,手机,邮箱,日期,金额的正则判定操作技巧,需要的朋友可以参考下
    2017-03-03

最新评论