Read DelayQueen source code

//A delayed fetch queue based on binary heap priority.
//Look at the constructor first.

public DelayQueue() {}

public DelayQueue(Collection<? extends E> c) {
        this.addAll(c);
    }

 //Insert the collection into the internal PriorityQueue.
 public boolean addAll(Collection<? extends E> c) {
        if (c == null)
            throw new NullPointerException();
        if (c == this)
            throw new IllegalArgumentException();
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }


    public boolean add(E e) {
        if (offer(e))
            return true;
        else
            throw new IllegalStateException("Queue full");
    }

//Insert elements are inserted into the internal PriorityQueue.
    public boolean offer(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            q.offer(e);
	    //If the header element is inserted (that is, the current header element has changed)
            if (q.peek() == e) {
	    //Set the leader thread to null
                leader = null;
            // wake up the waiting thread
                available.signal();
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

    public boolean offer(E e, long timeout, TimeUnit unit) {
        return offer(e);
    }


    public void put(E e) {
        offer(e);
    }
// get the element but don't remove it
     public E peek() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
	    //Use the underlying priorityQueue implementation.
            return q.peek();
        } finally {
            lock.unlock();
        }
    }

//Get the header element If the header element is empty or it has not been dequeued, return null.
     public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
	   // get the header element
            E first = q.peek();
	    //If the header element is empty or the obtained header element has not been dequeued, return null
            if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
                return null;
            else
                return q.poll();
        } finally {
            lock.unlock();
        }
    }

    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 empty
                if (first == null) {
		// time out and return null
                    if (nanos <= 0)
                        return null;
                    else
		    //Suspend the current thread nanos time
                        nanos = available.awaitNanos(nanos);
                } else {
                    long delay = first.getDelay(TimeUnit.NANOSECONDS);
		    // when it's time to take it out
                    if (delay <= 0)
                        return q.poll();
		    // time out and return null
                    if (nanos <= 0)
                        return null;
		    //If the waiting time is less than the dequeue time or the leader thread !=null, suspend the current thread
		    if (nanos < delay || leader != null)
                        nanos = available.awaitNanos(nanos);
                    else {
		    //If there is no other leader thread, set itself as the leader thread
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            long timeLeft = available.awaitNanos(delay);
                            nanos -= delay - timeLeft;
                        } finally {
			  //if the leader is himself
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
	    // release the lock
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }

//Blockable get queue head node
 public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                E first = q.peek();
		// if not obtained, wait
                if (first == null)
                    available.await();
                else {
                    long delay = first.getDelay(TimeUnit.NANOSECONDS);
                    //return the arrival queue dequeue time
		    if (delay <= 0)
                        return q.poll();
		    //If the leader is not equal to null, block the current thread and let the leader thread take the current element
                    else if (leader != null)
                        available.await();
                    else {
                        Thread thisThread = Thread.currentThread();
			//The current thread is set to the leader
                        leader = thisThread;
                        try {
			    //Wait for the delay time to wake up
                            available.awaitNanos(delay);
                        } finally {
			   //After waking up, if I am the leader, let other threads become the leader.
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
	    //If the leader is empty and there is a head to wake up other threads.
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }


    /** The leader thread is the thread that is currently getting the head node. When the offer is made, if the inserted element becomes the head node,
    At this time, the leader is set to null, and the competition for the leader is re-competed.
    DelayQueen uses a PriorityQueen class implementation internally, so the priority of the insertion order can be guaranteed.
    Then according to the getDelay method that implements the Delayed interface, get whether the element has reached the dequeue time.
    */

//get the queue length
    public int size() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.size();
        } finally {
            lock.unlock();
        }
    }
//Get the capacity (there is no capacity limit, so return the maximum value of integer)
public int remainingCapacity() {
        return Integer.MAX_VALUE;
    }

// remove element
public boolean remove(Object o) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.remove(o);
        } finally {
            lock.unlock();
        }
    }


 public Object[] toArray() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.toArray();
        } finally {
            lock.unlock();
        }
    }

public <T> T[] toArray(T[] a) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.toArray(a);
        } finally {
            lock.unlock();
        }
    }
// remove the available elements from the queue and wrap them in the collection
 public int drainTo (Collection <? super E> c) {
        if (c == null)
            throw new NullPointerException();
        if (c == this)
            throw new IllegalArgumentException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            int n = 0;
            for (;;) {
                E first = q.peek();
                if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
                    break;
                c.add(q.poll());
                ++n;
            }
            return n;
        } finally {
            lock.unlock();
        }
    }
// Remove at most maxElements available elements from the collection.
public int drainTo (Collection <? super E> c, int maxElements) {
        if (c == null)
            throw new NullPointerException();
        if (c == this)
            throw new IllegalArgumentException();
        if (maxElements <= 0)
            return 0;
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            int n = 0;
            while (n < maxElements) {
                E first = q.peek();
                if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
                    break;
                c.add(q.poll());
                ++n;
            }
            return n;
        } finally {
            lock.unlock();
        }
    }


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326489172&siteId=291194637