int loop() { long _fireTime; long t = System.currentTimeMillis(); BaseTimerTask e; int fireCnt = 0; for (; ; ) { boolean _fires; synchronized (timer.lock) { Queue q = timer.outQueue; for (; ; ) { e = q.getNextNotCancelledMin(); if (e == null) { return fireCnt; } _fires = false; _fireTime = e.getTime(); if (_fireTime > t) { t = System.currentTimeMillis(); } if (_fireTime <= t) { if (_fireTime < t) { // missed timely execution? recordLapse(_fireTime, t); } q.removeMin(); BaseTimerTask _next = q.getMin(); boolean _fireWithinLock = _next != null && _fireTime == _next.getTime(); if (_fireWithinLock) { fireTask(e); fireCnt++; continue; } _fires = true; } break; } // inner for loop } // synchronized if (_fires) { fireTask(e); fireCnt++; } else { long _waitTime = _fireTime - t; waitUntilTimeout(_waitTime); } } // outer loop }
void fireTask(BaseTimerTask e) { try { boolean f = e.fire(e.getTime()); if (f) { timer.eventsDelivered++; } else { cancelCount++; } } catch (Throwable ex) { timer.fireExceptionCount++; timer.log.warn("timer event caused exception", ex); } }
/** * Cleans cancelled timer tasks from the priority queue. We do this just in the thread that calls * us, but without holding up event delivery . When a purge occurs we work with two queues. One * for added timer tasks and one for delivered timer tasks. Newly added timer tasks will be * appended to the the out queue after the purge is finished. Thus, the delivery of new timer * tasks is delayed after the purge is finished. * * <p>One tricky thing is to catch up with tasks that fired during the purge from the out queue. * This is achieved by skipping to the time of the task that will fire next and by the ensurance * that the timer thread will always process events of the same time within one synchronized * block. */ void performPurge() { Queue _purgeQ; int _queueSizeBefore; synchronized (lock) { if (inQueue != outQueue || inQueue.size == 0) { return; } addedWithoutPurge = Integer.MIN_VALUE; cancelCount += inQueue.cancelCount; outQueue.cancelCount = 0; _purgeQ = outQueue.copy(); inQueue = new Queue(); _queueSizeBefore = outQueue.size; } _purgeQ.purge(); synchronized (lock) { boolean _somethingFired = outQueue.size != _queueSizeBefore; if (_somethingFired) { BaseTimerTask _nextTimerTaskInQueue = outQueue.getNextNotCancelledMin(); if (_nextTimerTaskInQueue == null) { cancelCount += outQueue.cancelCount; _purgeQ = new Queue(); } else { long _forwardUntilTime = _nextTimerTaskInQueue.getTime(); BaseTimerTask t; BaseTimerTask _previousSkippedTask = null; while ((t = _purgeQ.getMin()).getTime() != _forwardUntilTime) { if (t.isCancelled()) { _purgeQ.cancelCount++; } _purgeQ.removeMin(); _previousSkippedTask = t; } } } BaseTimerTask t; while ((t = inQueue.getNextNotCancelledMin()) != null) { inQueue.removeMin(); _purgeQ.addQueue(t); } cancelCount += inQueue.cancelCount; inQueue = outQueue = _purgeQ; addedWithoutPurge = 0; if (inQueue.size > 0) { startThread(); lock.notify(); } purgeCount++; } }