Springboot定时器多线程解决多个定时器冲突问题

本文探讨了SpringBoot定时器在并发场景下可能引发的问题,如单线程导致的定时器执行冲突和潜在的雪崩效应。通过引入多线程和线程池,解决了定时器的并发问题,确保了系统的稳定性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用场景 :

  1. 我们的订单服务,一般会有一个待支付订单,而这个待支付订单是有时间限制的,比如阿里巴巴的订单是五天,淘宝订单是一天,拼多多订单是一天,美团订单是15分钟…
  2. 基金系统中,如何同时更新多个存储分区中的基金信息…

总的来说,实际开发中定时器需要解决多个定时器同时并发的问题,也要解决定时器之间的冲突问题

问题不大,说到并发那就离不开多线程了…慢慢看看就懂了

问题场景重现 :

在这里插入图片描述
在这里插入图片描述

我们清晰的看到执行结果都是scheduling-1
就此可以判定,Springboot定时器默认的是单线程的

但是问题就来了,如果在线程争夺资源后,某个线程需要比较长时间才能执行完,那其他的定时器怎么办,都只能进入等待状态,时间越久,累计等待的定时器越多,这就容易引起雪崩…

其实只需要添加一个配置类然后加注解就可以解决问题了

添加注解

在这里插入图片描述

具体代码如下 :

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

import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class SchedulerTaskController {
    private Logger logger= LoggerFactory.getLogger(SchedulerTaskController.class);
    private static final SimpleDateFormat dateFormat=new SimpleDateFormat("HH:mm:ss");
    private int count=0;
    @Scheduled(cron="*/6 * * * * ?")
    @Async("threadPoolTaskExecutor")
    public void process(){
        logger.info("英文:this is scheduler task runing "+(count++));
    }

    @Scheduled(fixedRate = 6000)
    @Async("threadPoolTaskExecutor")
    public void currentTime(){
        logger.info("中文:现在时间"+dateFormat.format(new Date()));
    }
}

配置类如下 :

在这里插入图片描述

具体代码如下 :

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;



/**使用多线程的时候,往往需要创建Thread类,或者实现Runnable接口,如果要使用到线程池,我们还需要来创建Executors,
 * 在使用spring中,已经给我们做了很好的支持。只要要@EnableAsync就可以使用多线程
 * 通过spring给我们提供的ThreadPoolTaskExecutor就可以使用线程池。*/
//@Configuration 表示该类是一个配置类
@Configuration
@EnableAsync
//所有的定时任务都放在一个线程池中,定时任务启动时使用不同都线程。
public class TaskScheduleConfig {
    private static final int corePoolSize = 10;       		// 默认线程数
    private static final int maxPoolSize = 100;			    // 最大线程数
    private static final int keepAliveTime = 10;			// 允许线程空闲时间(单位:默认为秒),十秒后就把线程关闭
    private static final int queueCapacity = 200;			// 缓冲队列数
    private static final String threadNamePrefix = "it-is-threaddemo-"; // 线程池名前缀

    @Bean("threadPoolTaskExecutor") // bean的名称,默认为首字母小写的方法名
    public ThreadPoolTaskExecutor getDemoThread(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(keepAliveTime);
        executor.setKeepAliveSeconds(queueCapacity);
        executor.setThreadNamePrefix(threadNamePrefix);

        //线程池拒绝任务的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //初始化
        executor.initialize();

        return executor;
    }
}

然后我们可以很清晰地看到
在这里插入图片描述

如上,也就解决了用多线程解决Springboot多定时器冲突的问题

<think>好的,我现在需要帮用户找到低延迟定时任务的实现方法和替代方案。用户之前提到过一些引用内容,比如Timer类、@Scheduled注解、Quartz、时间轮算法等。我得先理清楚这些技术的优缺点,然后结合低延迟的需求来推荐合适的方案。 首先,用户提供的引用里提到Timer类有固定延迟的执行方式,但引用2也指出阿里巴巴规范建议用其他方案替代Timer,因为Timer是单线程的,可能会有任务堆积的问题,导致延迟增加。所以Timer可能不太适合低延迟场景。 接下来,引用4提到SpringBoot中的@Scheduled注解、Quartz和Timer。@Scheduled使用简单,但如果是单线程执行的话,任务多的时候也会有延迟。Quartz支持分布式和复杂调度,但可能因为其设计复杂而引入额外的开销,影响延迟。 引用3和用户的问题中提到了时间轮算法,比如RingBufferWheel。时间轮在任务调度中非常高效,适合处理大量的定时任务,尤其是任务到期检查的时间复杂度是O(1),这能有效降低延迟。所以时间轮应该是一个好的选择。 另外,用户可能还关心其他方案,比如Netty的HashedWheelTimer,这也是基于时间轮的实现。还有Kafka内部用的时间轮,处理大量延时消息。这些都应该考虑进去。 还有,是否需要考虑分布式环境?如果任务分布在多个节点上,可能需要分布式任务调度系统,比如Quartz集群或者Elastic Job。但用户的问题可能更偏向单机低延迟,所以可能先集中在单机方案上。 另外,操作系统级别的定时器,比如Linux的timerfd,或者使用epoll机制,可能提供更精确的定时,但实现起来比较复杂,需要结合具体编程语言和系统API。 再考虑编程语言,用户提供的示例代码是Python,但引用中的内容提到了Java的库,比如SpringBoot和Quartz。需要确认用户的技术栈,但用户没有明确说明,可能需要给出通用的方案。 综合来看,时间轮算法、HashedWheelTimer、以及基于事件循环的框架(如Netty)都是低延迟的解决方案。此外,使用优先级队列(最小堆)实现的定时任务调度,虽然插入是O(log n),但相比时间轮的O(1)可能稍慢,但在任务量不是极大的情况下也可以接受。 需要检查引用中的资料是否有其他方案。引用5提到除了Cron还有其他定时任务方案,可能包括系统级的定时器或者更高效的任务调度库。 总结可能的方案: 1. 时间轮算法(单机,高吞吐量,低延迟) 2. HashedWheelTimer(Netty的实现) 3. 基于事件循环的异步框架(如asyncio在Python中的使用) 4. 使用最小堆的优先级队列 5. 操作系统提供的精确定时器(如timerfd) 6. 分布式任务调度系统(如果涉及分布式,但可能增加延迟) 然后,需要将这些方案按照低延迟的要求排序,时间轮和HashedWheelTimer应该是首选。此外,注意线程模型,避免任务执行阻塞调度,比如使用多线程或异步非阻塞IO来处理任务执行。 可能还需要提到一些优化点,比如任务的分批处理、避免在任务中执行长时间阻塞操作、使用更高效的数据结构等。 最后,根据用户提供的引用,特别是引用3中的RingBufferWheel,可以推荐自定义时间轮或者现有的库。同时引用4提到的SpringBoot的@Scheduled可能不适合,但结合异步任务可能会改善,不过可能不如时间轮高效。 需要确保回答的结构清晰,分点列出方案,每个方案说明优点和适用场景,并引用相关的引用内容。比如在时间轮部分引用3和可能的引用5,在替代Timer时引用2和4。</think>针对低延迟定时任务的实现,以下方案可有效优化响应速度和精度: ### 一、时间轮算法(最优单机方案) 时间轮通过环状数组和指针移动实现任务触发,时间复杂度为$O(1)$,适合高频任务调度。例如: ```java // 基于时间轮的任务添加示例 timeWheel.addTask(task, delay); ``` 该方案在任务数量激增时仍保持稳定延迟,Kafka、Netty等高性能框架均采用此设计[^3][^5]。 ### 二、HashedWheelTimer(Netty实现) Netty提供的轻量级时间轮实现,支持纳秒级精度: ```java HashedWheelTimer timer = new HashedWheelTimer(10, TimeUnit.MILLISECONDS); timer.newTimeout(task, 100, TimeUnit.MILLISECONDS); ``` 通过哈希分桶机制降低冲突概率,实测可承载百万级任务调度[^3]。 ### 三、优先级队列+多线程 采用最小堆管理任务,结合线程池执行: ```python import heapq from threading import Timer tasks = [] heapq.heappush(tasks, (exec_time, task)) # 工作线程循环取出最近任务 while True: exec_time, task = heapq.heappop(tasks) Timer(exec_time - now(), task).start() ``` 时间复杂度为$O(\log n)$,适合中等规模任务量[^1]。 ### 四、操作系统级定时器 1. **Linux timerfd**:通过文件描述符通知事件 ```c int tfd = timerfd_create(CLOCK_MONOTONIC, 0); struct itimerspec new_value = {...}; timerfd_settime(tfd, 0, &new_value, NULL); ``` 2. **Epoll循环**:配合epoll_wait实现精确等待 可实现微秒级精度,但需要系统编程经验。 ### 五、优化实践建议 1. **任务分片**:将大任务拆分为多个可并行子任务 2. **异步执行**:使用协程/非阻塞IO避免线程阻塞 3. **预热策略**:预先加载高频任务到内存 4. **监控补偿**:通过心跳机制检测延迟并动态调整 ### 方案对比表 | 方案 | 精度 | 吞吐量 | 实现难度 | 适用场景 | |------|------|--------|----------|----------| | 时间轮 | 毫秒级 | 百万级 | 中 | 高频交易、游戏同步 | | HashedWheelTimer | 毫秒级 | 十万级 | 低 | 网络框架、RPC调用 | | 优先级队列 | 秒级 | 万级 | 低 | 常规业务系统 | | timerfd | 微秒级 | 十万级 | 高 | 实时音视频系统 | 实际选择时需考虑:任务密度(QPS)、精度要求、集群规模等因素。对于Java生态推荐HashedWheelTimer,C++/Go项目可考虑libevent等事件库实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值