优先级调度器和`时间轮`调度器

'时间轮'调度器

package com.demo.scheduler;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class PlatformLaneScheduler {
    // 平台配置类
    static class Platform {
        final String name;
        final long interval; // 执行间隔(毫秒)
        long nextAllowedTime; // 下次允许执行时间
        
        public Platform(String name, long intervalSeconds) {
            this.name = name;
            this.interval = intervalSeconds * 1000;
            this.nextAllowedTime = System.currentTimeMillis(); // 初始可立即执行
        }
    }
    
    // 全局状态
    private final Map<String, Platform> platforms = new HashMap<>();
    private long lastExecutionTime = 0; // 上次执行时间
    private final ScheduledExecutorService scheduler;
    
    public PlatformLaneScheduler() {
        // 初始化调度器(单线程)
        scheduler = Executors.newSingleThreadScheduledExecutor();
        
        // 添加平台配置
        addPlatform("A", 5);
        addPlatform("B", 3);
        addPlatform("C", 1);
    }
    
    public void addPlatform(String name, long intervalSeconds) {
        platforms.put(name, new Platform(name, intervalSeconds));
    }
    
    public void start() {
        // 每100ms巡检一次
        scheduler.scheduleAtFixedRate(this::checkPlatforms, 0, 100, TimeUnit.MILLISECONDS);
    }
    
    public void stop() {
        scheduler.shutdown();
    }
    
    private void checkPlatforms() {
        long now = System.currentTimeMillis();
        // 检查全局限流:1秒内只能执行一次
        if (now - lastExecutionTime < 1000) {
            return;
        }
        // 查找最早到期的平台
        Platform earliestPlatform = null;
        long minNextTime = Long.MAX_VALUE;
        for (Platform platform : platforms.values()) {
            if (platform.nextAllowedTime <= now && platform.nextAllowedTime < minNextTime) {
                earliestPlatform = platform;
                minNextTime = platform.nextAllowedTime;
            }
        }
        // 执行符合条件的平台请求
        if (earliestPlatform != null) {
            executePlatformRequest(earliestPlatform, now);
        }
    }
    
    private void executePlatformRequest(Platform platform, long now) {
        // 执行请求
        System.out.printf("[%tT.%tL] %s平台执行 | 设定间隔: %ds | 实际间隔: %.3fs%n",
                now, now, platform.name, platform.interval / 1000,
                (now - platform.nextAllowedTime + platform.interval) / 1000.0);
        // 更新平台状态
        platform.nextAllowedTime = now + platform.interval;
        // 更新全局状态
        lastExecutionTime = now;
    }
    
    public static void main(String[] args) throws InterruptedException {
        PlatformLaneScheduler laneScheduler = new PlatformLaneScheduler();
        laneScheduler.start();
        // 运行60秒
        TimeUnit.SECONDS.sleep(60);
        laneScheduler.stop();
    }
}

优先级队列调度器

package com.saturn.mail;

import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.*;

@Slf4j
public class DynamicScheduler {
    static class Platform {
        final String name;
        long minInterval; // 最小间隔(毫秒)
        long nextAllowedTime;
        long lastRequestTime;

        public Platform(String name, long minIntervalSeconds) {
            this.name = name;
            this.minInterval = minIntervalSeconds * 1000;
            this.nextAllowedTime = 0;
            this.lastRequestTime = -minInterval;
        }

    }

    private final PriorityQueue<Platform> queue = new PriorityQueue<>(
        Comparator.comparingLong(p -> p.nextAllowedTime)
    );

    private long lastGlobalRequestTime = System.currentTimeMillis() - 1000;
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    public DynamicScheduler() {
        addPlatform(new Platform("A", 6));
        addPlatform(new Platform("B", 3));
        addPlatform(new Platform("C", 10));

        startScheduling();
    }

    public synchronized void addPlatform(Platform platform) {
        // 直接加入队列
        queue.offer(platform);
        log.info("Added platform: {}" ,platform.name);
    }

    public synchronized void removePlatform(String name) {
        // 遍历找到并移除
        Platform toRemove = null;
        for (Platform p : queue) {
            if (p.name.equals(name)) {
                toRemove = p;
                break;
            }
        }
        if (toRemove != null) {
            queue.remove(toRemove);
            log.info("Removed platform: {}" , name);
        } else {
            log.info("Platform {} not found.",name);
        }
    }

    public synchronized void updatePlatformInterval(String name, long newMinIntervalSeconds) {
        // 遍历找到后更新
        Platform toUpdate = null;
        for (Platform p : queue) {
            if (p.name.equals(name)) {
                toUpdate = p;
                break;
            }
        }
        if (toUpdate != null) {
            queue.remove(toUpdate);
            toUpdate.minInterval = newMinIntervalSeconds * 1000;
            long now = System.currentTimeMillis();
            toUpdate.nextAllowedTime = Math.max(toUpdate.nextAllowedTime, now);
            queue.offer(toUpdate);
            log.info("Updated platform {} interval to {} seconds",name,newMinIntervalSeconds);
        } else {
            log.info("Platform {} not found.", name );
        }
    }

    private void startScheduling() {
        scheduler.scheduleAtFixedRate(() -> {
            try {
                scheduleNextRequest();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 0, 500, TimeUnit.MILLISECONDS);
    }

    private synchronized void scheduleNextRequest() {
        long now = System.currentTimeMillis();
        if (queue.isEmpty()) {
            return;
        }

        Platform platform = queue.peek();
        if (platform.nextAllowedTime <= now && (now - lastGlobalRequestTime) >= 1000) {
            queue.poll();

            log.info("Requesting platform:  {} at:{} " , platform.name , now);

            platform.lastRequestTime = now;
            platform.nextAllowedTime = now + platform.minInterval;
            lastGlobalRequestTime = now;

            queue.offer(platform);
        }
    }

    public void shutdown() {
        scheduler.shutdown();
    }

    public static void main(String[] args) throws InterruptedException {
        DynamicScheduler scheduler = new DynamicScheduler();

        Thread.sleep(10000);
        scheduler.addPlatform(new Platform("D", 5));
        Thread.sleep(5000);
        scheduler.updatePlatformInterval("B", 8);
        Thread.sleep(5000);
        scheduler.removePlatform("A");

        Thread.sleep(10000);
        scheduler.shutdown();
    }
}

参考博客:

  1. 也是出息了,业务代码里面也用上算法了。
  2. 糊涂啊!这个需求居然没想到用时间轮来解决。
posted @ 2025-08-13 10:38  lyu6  阅读(6)  评论(0)    收藏  举报