ScheduledThreadPoolExecutor实现限流算法

介绍

正常情况下,定时器我们都是用Timer和TimerTask这两个类就能完成定时任务,并且设置延长时间和循环时间间隔。
ScheduledThreadPoolExecutor也能完成Timer一样的定时任务,并且时间间隔更加准确。

我在后台程序看看一下Timer执行程序是有可能延迟1、2毫秒,如果是1秒执行一次的任务,1分钟有可能延迟60毫秒,一小时延迟3600毫秒,相当于3秒,实际用户看不出什么区别。
但是,如果我的程序需要每40毫秒就执行一次任务,如果还是有1、2毫秒的误差,1秒钟就有25毫秒的误差,大概40秒就有1秒的误差,十几分钟就有十几秒的误差,这对UI显示来说是延迟非常严重的了。
而我用ScheduledThreadPoolExecutor来做40毫秒的间隔任务,一般十几分钟才有1秒多的误差,这个还是能接受的。
这也是我用ScheduledThreadPoolExecutor这个类的原因。

使用Timer和TimerTask存在一些缺陷

  1. Timer只创建了一个线程。当你的任务执行的时间超过设置的延时时间将会产生一些问题。
  2. Timer创建的线程没有处理异常,因此一旦抛出非受检异常,该线程会立即终止。

JDK 5.0以后推荐使用ScheduledThreadPoolExecutor。该类属于Executor Framework,它除了能处理异常外,还可以创建多个线程解决上面的问题

令牌桶的Java实现

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


class Schedule {
    //增长速率
    static int RATE = 4;
    //桶最大值
    static int TOTAL = 10;
    //初始值
    static int WATER = 0;
    ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(2);

    public void run(){
        executorService.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                WATER = Math.min(WATER + RATE,TOTAL);
            }
        },0,1000, TimeUnit.MILLISECONDS);
    }

    public static synchronized boolean tryAcquire(int num){
        if (WATER >= num){
            WATER -= num;
            return true;
        }
        return false;
    }
    public static void main(String[] args) throws InterruptedException {
        Schedule schedule = new Schedule();
        schedule.run();
        for (int i = 1; i < 20; i++){
            if (tryAcquire(i)){
                System.out.println("拿到了" + i);
            }else{
                System.out.println("拿不到" + i);
            }
            try {
                Thread.sleep(500);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

   转载规则


《ScheduledThreadPoolExecutor实现限流算法》 锦泉 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录