Delayqueue, a thread-safe queue with deferred elements that returns an element that reaches the earliest delay time when non-blocking fetches an element from the queue, or empty (no element reaches the delay time). The generic parameters of the delayqueue need to implement the delayed interface, the delayed interface inherits the comparable interface, Delayqueue internally uses a non-thread-safe priority queue (Priorityqueue), and uses the leader/ Followers mode, minimizing unnecessary wait times. Delayqueue does not allow the inclusion of a null element.
A leader/follower pattern is a pattern in which multiple worker threads take turns to get the collection of event sources and listen, distribute, and handle events in turn. At any point in time, the program has only one leader thread, which is responsible for monitoring IO events. While other threads are followers, they hibernate in the thread pool waiting to become the new leader. Current leader If an IO event is detected, the first step is to select a new leader thread from the thread pool and then handle the IO event. At this point, the new leader waits for the new IO event, and the original leader handles the IO event, both of which implement concurrency.
The simple understanding is that at most one thread is processing, and the other threads are sleeping. In the implementation of Delayqueue, the leader/followers mode is used to wait for the first element of the first team.
Class definitions and Parameters:
public class Delayqueue<e extends delayed> extends abstractqueue<e> implements Blockingqueue<e> { /** re-enter lock for thread safety * /private final transient reentrantlock lock = new Reentrantlock (); /** is implemented using the priority queue * /private final priorityqueue<e> q = new priorityqueue<e> (); /** leader/followers mode */ private Thread Leader = null; The/** condition object, when a new element arrives, or a new thread may need to be leader, is notified */ private final Condition available = Lock.newcondition ();
constructor function:
/** * Default construct, get empty delay queue * /Public Delayqueue () {} /** * Constructs delay queue, initial contains elements in c * * @param c The initially contained collection of elements * @throws nullpointerexception throws a null pointer error when any element of the collection or collection is empty * /Public delayqueue (collection<? Extends e> c) { this.addall (c); }
Add Method:
/** * Insert element into delay queue * * @param e element to insert * @return true * @throws nullpointerexception element is empty, throws null pointer error * /public boolean add (E e) { //call offer directly and return to offer (e); }
Offer method:
/** * Insert element into delay queue * * @param e element to insert * @return true * @throws nullpointerexception element is empty, throws null pointer error * /public boolean offer (E e) { final reentrantlock lock = This.lock; Get lock Lock.lock (); try { //Insert element Q.offer to Priority queue (e); If the queue is empty before this, then empty leader, and notify the conditional object, need to combine take method to see if (q.peek () = = e) { leader = null; Available.signal (); } return true; } finally { //release lock Lock.unlock (); } }
Put method:
/** * Inserts an element into the delay queue. Because the queue is unbounded, it does not block. * * @param e element to be inserted * @throws the NullPointerException element is empty, throws a null pointer error * /public void put (E-e) { offer (e); }
Offer method with timeout:
/** * Inserts an element into the delay queue. Because the queue is unbounded, it is not blocked, so call the Offer method directly and return * * @param e The element to insert * @param timeout will not block, ignore * @param unit does not block, ignores * @return true * @throws nullpointerexception element is empty, throws null pointer error */public Boolean offer (e E, long timeout, timeunit unit) { //Call the Offer method directly and return to offer (e); }
Poll Method:
/** * Gets and removes the element of the first line, or returns null if the queue does not contain elements that arrive at the delay time * * @return Elements of the first team, or null (if the queue does not contain elements that arrive at the delay time) */ Public E Poll () { final reentrantlock lock = This.lock; Get lock Lock.lock (); try { //Get priority queue first element E initial = Q.peek (); Returns null if the first element of the priority queue is empty, or if the delay time has not yet been reached, the return null if (initial = = NULL | | first.getdelay (nanoseconds) > 0) return nulls; Otherwise, return and remove the team first element else return Q.poll (); } finally { //release lock Lock.unlock (); } }
Take method (important):
/** * Gets and removes the first element of the team, the method blocks until the queue contains an element that reaches the delay time * * @return Team first element * @throws interrupted when Interruptedexception blocked, throws a break exception */Public E take () throws Interruptedexception {final Reentrantlock lock = This.lock; To obtain a lock, the lock can be interrupted by lock.lockinterruptibly (); try {//loop processing for (;;) {//Get the first element of the team, E: Q.peek (); If the element is empty, wait for the condition, the notification method of the conditional object is called in the Offer method//and re-enters the loop if (first = = null) availab Le.await (); If the element is not empty else {//Gets the delay time long delay = First.getdelay (nanoseconds); If the delay time is reached, return and remove the team first element if (delay <= 0) return Q.poll (); Otherwise, you need to enter wait first = NULL; When waiting, do not hold the reference//if leader is not empty, wait for the condition if (leader! = NULL) availabl E.await (); Otherwise, the leader is set to the current thread, and the timeout waits for the delay time else {thread thisthread = Thread.curr Entthread (); leader = Thisthread; try {Available.awaitnanos (delay); } finally {if (leader = = Thisthread) leader = null; }}}}} finally {//notify other thread conditions to be satisfied if (leader = = null && q.peek ()! = null) available.signal (); Release lock Lock.unlock (); } }
Poll method with timeout (important):
/** * Gets and removes the first element of the team, the method blocks until the queue contains an element that reaches the delay time or times out * * @return The first element of the team, or null * @throws interruptedexception blocking wait When interrupted, throws an interrupt exception */Public E poll (long timeout, timeunit unit) throws Interruptedexception {Long Nanos = Unit.tonanos (timeout); Final Reentrantlock lock = This.lock; Lock.lockinterruptibly (); try {for (;;) {E first = Q.peek (); if (first = = null) {if (Nanos <= 0) return null; else Nanos = Available.awaitnanos (Nanos); } else {Long delay = First.getdelay (nanoseconds); if (delay <= 0) return Q.poll (); if (Nanos <= 0) return null; first = null; Don ' t retain ref while waiting if (Nanos < delay | | Leader! = NULL) Nanos = Available. Awaitnanos (Nanos); else {Thread thisthread = Thread.CurrentThread (); leader = Thisthread; try {Long timeLeft = Available.awaitnanos (delay); Nanos-= Delay-timeleft; } finally {if (leader = = Thisthread) leader = null; }}}}} finally {if (leader = = NULL &&A mp Q.peek ()! = null) available.signal (); Lock.unlock (); } }
Peek Method:
/** * Gets but does not remove the first element of the team, or returns null if the queue is empty. Unlike the poll method, * If the queue is not empty, the method returns to the first element of the team, regardless of whether the delay time is reached * @return Team first element, or null (if the queue is empty) */public E Peek () { final Reentrantlock lock = This.lock; Lock.lock (); try { return Q.peek (); } finally { lock.unlock (); } }
Source:
Https://www.cnblogs.com/enumhack/p/7472873.html
Https://www.cnblogs.com/wanly3643/p/3944661.html
JDK Source code
"Java concurrency Programming" 19, Delayqueue Source Analysis