java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot时间轮延时任务

SpringBoot时间轮实现延时任务的示例代码

作者:风象南

在日常开发中,我们经常需要处理各种定时任务:用户注册后的欢迎邮件、订单超时自动取消、缓存定期刷新等,传统的定时器方案在面对大规模定时任务时往往力不从心,所以本文给大家介绍了SpringBoot时间轮实现延时任务,需要的朋友可以参考下

传统方案的困境

在日常开发中,我们经常需要处理各种定时任务:用户注册后的欢迎邮件、订单超时自动取消、缓存定期刷新等。传统的定时器方案在面对大规模定时任务时往往力不从心:

性能瓶颈日益凸显

业务需求日益复杂

时间轮的诞生

时间轮(Timing Wheel) 灵感来源于我们日常使用的时钟。想象一下老式机械表的工作原理

时间轮借鉴了这个思想,将时间划分成固定的槽位,通过指针的移动来调度任务。这种巧妙的设计将时间维度空间化,用简单的指针移动代替了复杂的堆操作。

核心设计哲学

时间离散化:将连续时间分割成等长的tick间隔

空间映射:每个时间间隔对应一个槽位

批量触发:同一槽位的任务一起执行

轮次计数:多圈任务通过轮数计算

为什么时间轮如此高效?

时间轮的巧妙之处在于它彻底改变了任务调度的思路:

时间复杂度的革命 从O(log n)到O(1)

内存访问的优化

批量处理的威力

算法设计:从时钟模型到数据结构

时间轮的工作原理

想象一个真实的时钟

时间轮采用了类似的概念

核心数据结构设计

时间轮主体结构

时间轮数组:
[Slot0][Slot1][Slot2]...[Slot511]
  ↑       ↑       ↑         ↑
 指针    100ms后   200ms后    51.1秒后

槽位(Slot)设计

任务包装器(TimerTaskWrapper)

算法关键步骤

任务调度算法

  1. 计算任务需要经过的tick数量:ticks = delayMs / tickDuration
  2. 计算目标槽位:targetSlot = (currentSlot + ticks) % slotSize
  3. 计算需要经过的轮数:rounds = ticks / slotSize
  4. 将任务包装后放入目标槽位

指针移动算法

  1. 周期性地将指针移动到下一个槽位
  2. 处理当前槽位中的所有任务
  3. 对于未到期的任务,轮数减1后重新入槽
  4. 对于到期的任务,提交到工作线程池执行

多轮任务处理

核心实现:高性能调度引擎

线程模型设计

双线程池架构是时间轮高性能的关键

调度线程池(单线程):
    ↓
周期性移动指针
    ↓
处理槽位任务
    ↓
提交到工作线程池

工作线程池(多线程):
    ↓
并发执行任务
    ↓
处理业务逻辑
    ↓
更新任务状态

调度线程池

SpringBoot的完整实现

服务层

TimingWheelService设计

@Service
public class TimingWheelService {
    // 任务管理
    public String scheduleTask(TimerTask task, long delayMs);
    public boolean cancelTask(String taskId);
    public List<TimerTaskWrapper> getActiveTasks();

    // 统计信息
    public TimingWheelStats getStats();
    public TaskExecutionStats getExecutionStats();

    // 任务清理
    public int cleanupCompletedTasks();

    // 示例任务
    public String createSampleTask(String type, long delayMs);
    public List<String> createBatchTasks(int count, long minDelay, long maxDelay);
}

核心配置类

/**
 * 时间轮配置类
 */
@Configuration
@EnableConfigurationProperties(TimingWheelProperties.class)
public class TimingWheelConfig {

    @Bean
    public TimingWheel timingWheel(TimingWheelProperties properties, MeterRegistry meterRegistry) {
        log.info("Creating timing wheel with properties: {}", properties);
        return new TimingWheel(properties, meterRegistry);
    }

    @Bean
    public MetricsConfig metricsConfig(MeterRegistry meterRegistry) {
        return new MetricsConfig(meterRegistry);
    }

    @Bean
    public WebConfig webConfig() {
        return new WebConfig();
    }
}

REST API接口

/**
 * 时间轮控制器
 */
@RestController
@RequestMapping("/api/timingwheel")
@CrossOrigin(origins = "*")
public class TimingWheelController {

    @Autowired
    private TimingWheelService timingWheelService;

    /**
     * 获取时间轮统计信息
     */
    @GetMapping("/stats")
    public ResponseEntity<TimingWheel.TimingWheelStats> getStats() {
        TimingWheel.TimingWheelStats stats = timingWheelService.getStats();
        return ResponseEntity.ok(stats);
    }

    /**
     * 创建示例任务
     */
    @PostMapping("/tasks/sample")
    public ResponseEntity<Map<String, Object>> createSampleTask(@RequestBody Map<String, Object> request) {
        String type = (String) request.getOrDefault("type", "simple");
        long delay = ((Number) request.getOrDefault("delay", 1000)).longValue();

        String taskId = timingWheelService.createSampleTask(type, delay);

        Map<String, Object> response = new HashMap<>();
        response.put("taskId", taskId);
        response.put("type", type);
        response.put("delay", delay);
        response.put("message", "Task created successfully");

        return ResponseEntity.ok(response);
    }

    /**
     * 批量创建任务
     */
    @PostMapping("/tasks/batch")
    public ResponseEntity<Map<String, Object>> createBatchTasks(@RequestBody Map<String, Object> request) {
        int count = (Integer) request.getOrDefault("count", 10);
        long minDelay = ((Number) request.getOrDefault("minDelay", 1000)).longValue();
        long maxDelay = ((Number) request.getOrDefault("maxDelay", 10000)).longValue();

        List<String> taskIds = timingWheelService.createBatchTasks(count, minDelay, maxDelay);

        Map<String, Object> response = new HashMap<>();
        response.put("taskIds", taskIds);
        response.put("count", taskIds.size());
        response.put("message", "Batch tasks created successfully");

        return ResponseEntity.ok(response);
    }

    /**
     * 压力测试
     */
    @PostMapping("/stress-test")
    public ResponseEntity<Map<String, Object>> stressTest(@RequestBody Map<String, Object> request) {
        int taskCount = (Integer) request.getOrDefault("taskCount", 1000);
        long minDelay = ((Number) request.getOrDefault("minDelay", 100)).longValue();
        long maxDelay = ((Number) request.getOrDefault("maxDelay", 5000)).longValue();

        long startTime = System.currentTimeMillis();
        List<String> taskIds = timingWheelService.createBatchTasks(taskCount, minDelay, maxDelay);
        long endTime = System.currentTimeMillis();

        Map<String, Object> response = new HashMap<>();
        response.put("taskCount", taskIds.size());
        response.put("creationTime", endTime - startTime);
        response.put("throughput", taskIds.size() * 1000.0 / (endTime - startTime));
        response.put("message", "Stress test completed successfully");

        return ResponseEntity.ok(response);
    }
}

应用配置

# application.yml
server:
  port: 8081
  servlet:
    context-path: /

spring:
  application:
    name: springboot-timingwheel

# Timing Wheel Configuration
timingwheel:
  config:
    slot-size: 512
    tick-duration: 100
    worker-threads: 4
    enable-multi-wheel: true
    enable-metrics: true
    task-timeout: 30000

logging:
  level:
    com.example.timingwheel: DEBUG
    org.springframework.web: INFO
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

总结

本文展示了时间轮的设计与实现,从算法原理到可视化监控。时间轮通过巧妙的时间维度空间化思想,用简单的指针移动实现了高效的定时任务调度,在高并发场景下展现出卓越的性能优势。

以上就是SpringBoot时间轮实现延时任务的示例代码的详细内容,更多关于SpringBoot时间轮延时任务的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文