What would be a real world usage of DelayQueue, what common problem it was designed to solve?
5 Answers
I recently used a delay queue for rate limiting.
For a limit of X events per second, place each event into a delay queue with a 1 second delay.
If there are X events on the delayQueue, take() from the queue (which blocks until at least 1 expires). That way you allow a short term burst, without exceeding any long-term limits.
This class is perfect for a thread that wants to process multiple delayed events their proper order.
Suppose, for example, you have a display with 100 flashing lights, and all the lights flash at different unrelated rates. You could have a thread for each light, or you could have one thread coordinate all of them using this class. It would work something like this:
- have a
Light
class with a flash rate - create an implementation of the
Delayed
interface that points to the light, sayLightFlash
- create your
DelayQueue
and add a newLightFlash
for each light, with the delay set appropriate for the light's flash rate - loop:
- get an event with DelayQueue::take().
- toggle the light on/off
- add a new event to the queue for the light's next flash with DelayQueue::put(E).
DelayQueue takes care of getting the next event to process.
Two real-world examples I can think of:
- A (non-multithreaded) server that needs to perform certain timed actions, e.g. connection ping on each connection.
- An implementation of a javascript-enabled browser, that needs to deal with the arbitrary number of timed events created with setInterval() and setTimeout(). Oh, and animated GIFs.
DelayQueue
is probably implemented as a priority queue, which is generally best implemented as a heap.
the main usage would be task timers like the for Timer classes
if one could make the delay independant from the system clock (which I beleive you can, not sure though) you can use it for game events like "after 5 ticks move to X" (otherwise clock jitter wold make this unreliable)
Note that the delays are associated with the elements that go on the queue rather than the queue itself. Some objects that go into the queue could have a delay of zero, whilst some can have a much longer delay:
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Delayed.html
With this in mind, I can think of a few use cases - though they would probably be fragile and a bit of a code smell with regards to your messaging flow. I'd use alternatives to all of them except in specific situations:
1) Control flow - we know that an order takes 60 seconds to process, so don't read the next order off of the queue until the object has been there for at least 60 seconds.
2) Message flow - A highly asynchronous system where we send off requests to 2 or 3 external services and then release the next task to process the order N seconds later once we know the first batch of jobs will at least have had a chance of completing.
3) Message batching - maybe orders of a certain type are bursty, so lets not process orders received in the last N seconds so we can see if similar orders come in shortly after that can be processed as a batch on the next run.
4) Message priorities - different messages or different customers could get a slightly higher quality of service with a lower or zero delay.
In some cases, objects that you place on a queue should be on that queue for a certain amount of time before they are ready to be dequeued. This is where you use the java.util.concurrent.DelayQueue class, which implements the BlockingQueue interface. The DelayQueue requires that queue objects be resident on the queue for a specified amount of time.
For real world usage example see Minding the Queue article at devx site
...The real world example that I thought of to illustrate this (which might make you hungry) involves muffins. Well, Muffin objects (as we are talking Java—no coffee pun intended). Suppose you have a DelayQueue upon which you place Muffin objects... The getDelay method, in essence, states how much time is left for the object to be kept in the DelayQueue. When the number returned by this method becomes zero or less than zero, the object is ready (or in this example, baked) and allowed to be dequeued...
Since you don't really want to eat a Muffin that's not fully cooked, place the Muffin on the DelayQueue for the recommended cooking time...
-
1I understand what it does, but not what common problem it was designed to resolve, I'm looking for the use case(s) May 2, 2012 at 8:24