Posted on 2010-10-22 15:52
dennis 閱讀(4708)
評論(4) 編輯 收藏 所屬分類:
java 、
my open-source
今年在閱讀某個項目源碼的時候看到DelayQueue的使用,
xmemcached 1.2.6.1的重連任務也是采用DelayQueue管理,ReconnectRequest實現Delayed接口,我突然想起去review下xmc的源碼,發現一個嚴重的BUG,原始代碼如下:
public final class ReconnectRequest implements Delayed {
public long getDelay(TimeUnit unit) {
return nextReconnectTimestamp - System.currentTimeMillis();
}
}
getDelay返回該任務還剩下多少時間可以被執行,將下次執行的時間戳減去當前時間即可,問題在于這里返回的是毫秒,而沒有調用getDelay傳入的TimeUnit做轉換,在DelayQueue內部其實是用納秒做單位交給Condition對象去等待
for (;;) {
E first = q.peek();
if (first == null) {
available.await();
} else {
long delay = first.getDelay(TimeUnit.NANOSECONDS);
if (delay > 0) {
long tl = available.awaitNanos(delay);
} else {
E x = q.poll();
assert x != null;
if (q.size() != 0)
available.signalAll(); // wake up other takers
return x;
}
}
}
最終導致的問題是,
awaitNanos很快返回(awaitNanos接受的是納秒,這里卻傳入毫秒),循環執行發現重新計算的delay仍然大于0,循環等到getDelay返回的越來越小直到0才執行相應的Task,,造成的現象是在重連的時候cpu占用率很高。
單元測試的時候沒有發現這個問題,主要是因為功能正常,沒有關注資源消耗情況,因此慚愧地忽略了。
解決的辦法很簡單,修改getDelay方法即可:
public long getDelay(TimeUnit unit) {
return unit.convert(
nextReconnectTimestamp - System.currentTimeMillis(),
TimeUnit.MILLISECONDS);
}
這個BUG比較嚴重,已經升級1.2.6.1的朋友建議馬上升級到1.2.6.2,使用maven的朋友只要修改版本即可,沒有使用maven的請到這里下載。