/** * Retrieve, but does not remove, the head of this queue, or returns <tt>null</tt> if this queue * is empty. Unlike <tt>poll</tt>, if no expired elements are available in the queue, this method * returns the element that will expire next, if one exists. * * @return the head of this queue, or <tt>null</tt> if this queue is empty. */ @Override public QueueElement<E> peek() { lock.lock(); try { antiStarvation(); QueueElement<E> e = null; QueueElement<E>[] seeks = new QueueElement[priorities]; boolean foundElement = false; for (int i = priorities - 1; i > -1; i--) { e = queues[i].peek(); debug("peek(): considering [{0}] from P[{1}]", e, i); seeks[priorities - i - 1] = e; foundElement |= e != null; } if (foundElement) { e = null; for (int i = 0; e == null && i < priorities; i++) { if (seeks[i] != null && seeks[i].getDelay(TimeUnit.MILLISECONDS) > 0) { debug("peek, ignoring [{0}]", seeks[i]); } else { e = seeks[i]; } } if (e != null) { debug("peek(): choosing [{0}]", e); } if (e == null) { int first; for (first = 0; e == null && first < priorities; first++) { e = seeks[first]; } if (e != null) { debug("peek(): initial choosing [{0}]", e); } for (int i = first; i < priorities; i++) { QueueElement<E> ee = seeks[i]; if (ee != null && ee.getDelay(TimeUnit.MILLISECONDS) < e.getDelay(TimeUnit.MILLISECONDS)) { debug("peek(): choosing [{0}] over [{1}]", ee, e); e = ee; } } } } if (e != null) { debug("peek(): [{0}], from P[{1}]", e.getElement().toString(), e.getPriority()); } else { debug("peek(): NULL"); } return e; } finally { lock.unlock(); } }
/** * Insert the specified {@link QueueElement} element into the queue. * * @param queueElement the {@link QueueElement} element to add. * @param ignoreSize if the queue is bound to a maximum size and the maximum size is reached, this * parameter (if set to <tt>true</tt>) allows to ignore the maximum size and add the element * to the queue. * @return <tt>true</tt> if the element has been inserted, <tt>false</tt> if the element was not * inserted (the queue has reached its maximum size). * @throws NullPointerException if the specified element is null */ boolean offer(QueueElement<E> queueElement, boolean ignoreSize) { if (queueElement == null) { throw new NullPointerException("queueElement is NULL"); } if (queueElement.getPriority() < 0 || queueElement.getPriority() >= priorities) { throw new IllegalArgumentException("priority out of range: " + queueElement); } if (queueElement.inQueue) { throw new IllegalStateException("queueElement already in a queue: " + queueElement); } if (!ignoreSize && currentSize != null && currentSize.get() >= maxSize) { return false; } boolean accepted; lock.lock(); try { accepted = queues[queueElement.getPriority()].offer(queueElement); debug( "offer([{0}]), to P[{1}] delay[{2}ms] accepted[{3}]", queueElement.getElement().toString(), queueElement.getPriority(), queueElement.getDelay(TimeUnit.MILLISECONDS), accepted); if (accepted) { if (currentSize != null) { currentSize.incrementAndGet(); } queueElement.inQueue = true; } } finally { lock.unlock(); } return accepted; }
/** * Promote elements beyond max wait time from a lower priority sub-queue to a higher priority * sub-queue. * * @param lowerQ lower priority sub-queue. * @param higherQ higher priority sub-queue. * @param msg sub-queues msg (from-to) for debugging purposes. */ private void antiStarvation( DelayQueue<QueueElement<E>> lowerQ, DelayQueue<QueueElement<E>> higherQ, String msg) { int moved = 0; QueueElement<E> e = lowerQ.poll(); while (e != null && e.getDelay(TimeUnit.MILLISECONDS) < -maxWait) { e.setDelay(0, TimeUnit.MILLISECONDS); if (!higherQ.offer(e)) { throw new IllegalStateException( "Could not move element to higher sub-queue, element rejected"); } e.priority++; e = lowerQ.poll(); moved++; } if (e != null) { if (!lowerQ.offer(e)) { throw new IllegalStateException( "Could not reinsert element to current sub-queue, element rejected"); } } debug("anti-starvation, moved {0} element(s) {1}", moved, msg); }