/**
* Get the window at current timestamp.
*
* @return the window at current timestamp
*/
public WindowWrap<T> currentWindow() {
return currentWindow(TimeUtil.currentTimeMillis());
}
/**
* Get window at provided timestamp.
*
* @param time a valid timestamp
* @return the window at provided timestamp
*/
public WindowWrap<T> currentWindow(long time) {
// 获取当前毫秒对应到window length的一个id
long timeId = time / windowLengthInMs;
// Calculate current index.
// 获取这个id对应到滚动数组中的具体index
// 通过mod操作完成了数组的滚动
int idx = (int)(timeId % array.length());
// Cut the time to current window start.
// 计算出这个window对应的开始时间戳
time = time - time % windowLengthInMs;
// 自旋循环开始
while (true) {
// 获取index对应的窗口
WindowWrap<T> old = array.get(idx);
if (old == null) {
// 如果是null, 说明出于滚动窗口初始化阶段
// 创建一个新的窗口,通过调用newEmptyBucket来获取新的统计桶
WindowWrap<T> window = new WindowWrap<T>(windowLengthInMs, time, newEmptyBucket());
// CAS 设置 AtomicReferenceArray里面对应的元素
if (array.compareAndSet(idx, null, window)) {
// 如果设置成功就返回当前的window
return window;
} else {
// 如果不成功调用 线程让步
// 进入下一次自旋循环
Thread.yield();
}
} else if (time == old.windowStart()) {
// 如果开始时间与现存的窗口的开始时间一致
// 表明请求时间戳与现存的窗口匹配,因此直接返回
return old;
} else if (time > old.windowStart()) {
// 如果请求的时间戳大于现存的窗口的开始时间
// 说明当前的窗口已经是陈旧的,也就是属于已经过去的一个统计时长之外的数据
// 因此需要重置窗口的数据
if (updateLock.tryLock()) {
try {
// 尝试获取update锁成功
// 调用resetWindowTo方法重置
// if (old is deprecated) then [LOCK] resetTo currentTime.
return resetWindowTo(old, time);
} finally {
updateLock.unlock();
}
} else {
// 如果获取锁失败,说明已经有其他线程获取锁并进行更新
// 因此调用线程让步 并进入下一次自旋循环
Thread.yield();
}
} else if (time < old.windowStart()) {
// 如果请求的时间比现存的还小,直接返回一个空的,说明这次请求的时间戳已经陈旧了
// Cannot go through here.
return new WindowWrap<T>(windowLengthInMs, time, newEmptyBucket());
}
}
}
07-17
02-20
755
06-25