java实现令牌桶算法

此实现是根据GUAVA实现的令牌桶算法限流的思路,在每次尝试获取token时进行计算当前可获得的token数量,相当于懒汉式生成令牌,无需额外的线程去生成令牌。况且,额外线程去生成令牌,需要消耗线程资源,在并发量较高时,定时任务并不准确,不能准确生成令牌。

package concurrencylimit;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 令牌桶算法
 *
 * @author nekle
 * @since 2022/8/9
 */
public class TokenBucket {
	// 上一次获取令牌的时间
    private AtomicLong beforeAtomic;
    // 生成令牌的时间间隔
    private int interval;
    // 最大令牌数量
    private int max;
    // 用于控制令牌数量修改的可重入锁
    private ReentrantLock lock;
    public TokenBucket(int interval, int max) {
        this.beforeAtomic = new AtomicLong(System.currentTimeMillis() - interval * max);
        this.interval = interval;
        this.max = max;
        this.lock = new ReentrantLock(true);
    }

    public boolean acquire() {
        boolean flag = false;
        // 当前线程自旋尝试获取令牌
        while (!flag) {
        	// 当前获取令牌时间
            long now = System.currentTimeMillis();
            // 上一次获取令牌时间
            long before = this.beforeAtomic.get();
            // 计算时间间隔内生成的令牌数
            long tokenSum = ((now - before) / interval);
            // 有剩余令牌,则尝试获取令牌
            if (tokenSum > 0) {
                boolean locked = false;
                // 如果令牌数量超过设置的上限,则将令牌数量归于上限值
                if (tokenSum > max) {
                	// 可重入锁对令牌数修改操作进并发访问控制
                    locked = lock.tryLock();
                    if (locked) {
                    	// 成功拿到锁,则进行修改,将令牌数量归于上限值
                        this.beforeAtomic.set(now - interval * max + interval);
                        flag = true;
                        lock.unlock();
                    }
                }
                // 若尝试获得锁失败,说明另一个线程正在修改最后一次获得令牌的时间
                if (!locked) {
                	// CAS尝试修改最后一次获取令牌的时间,成功则完成这次获取令牌操作,否则继续自旋尝试获得令牌
                    flag = this.beforeAtomic.compareAndSet(before, before + interval);
                }
            } else {
            	// 无剩余令牌,尝试获取令牌失败
                return false;
            }
        }
        return true;
    }
}

最近在学习令牌桶算法,自己实现了一个,欢迎各位交流学习!!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值