DelayQueue learning

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/ko0491/article/details/90905541

DelayQueue a concurrent queue is unbounded blocking delay queue, the queue of each element has an expiration time,
when acquiring an element from the queue, the queue will only expire elements. Head of the queue element is the fastest to expire elements.
Here Insert Picture Description

public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
    implements BlockingQueue<E> {

    private final transient ReentrantLock lock = new ReentrantLock();
    private final PriorityQueue<E> q = new PriorityQueue<E>();
     private Thread leader = null;
    private final Condition available = lock.newCondition();

    public DelayQueue() {}


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


Operation offer

    public boolean offer(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            q.offer(e);
            if (q.peek() == e) {
                leader = null;
                available.signal();
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

Obtaining an exclusive lock code first, and then add elements to the priority queue, since q is the priority queue, so
the additional element, calling q.peek () method returns the current element is not necessarily added. If the code (2) determination
result is true, then the current element e is the first to expire, resetting the leader thread is null, which when excited
living condition variables avaliable inside a thread queue, the queue to tell it inside the element .

take operational

Retrieves and removes the delay time expired queue inside the element, if there is no queue waiting for the expiration element


 public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
            //1 获取但不移除队首元素
                E first = q.peek();
                if (first == null)
                //2 阻塞 进入等待
                    available.await();
                else {
                    long delay = first.getDelay(NANOSECONDS);
                    //3 时间小于=于0
                    if (delay <= 0)
                        return q.poll();
                    first = null; // don't retain ref while waiting
                    if (leader != null)
                        available.await();
                    else {
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            available.awaitNanos(delay);
                        } finally {
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }

First, acquire an exclusive lock lock. A thread queue is assumed to take the first method call queue
empty, is performed after the first == null code is 1, it executes the code. The current thread into the available Article
pieces blocked waiting queue.

When another thread B executed offer (item) element is added to the queue and method, assuming that no
other thread performs enqueue operation, element B is added to the thread elements of the first team, is executed q.peek ()

A thread is withdrawn and re-live the team get the first element of the cycle, this time the first thread B is the new element, can
know this first time is not null, is invoked first. GetDelay (TimeUnit.NANOSECONDS) way to see the element
also remaining how much time will expire, if the de lay <= O then the period has elapsed, then direct the team to return. Otherwise, check
to see if the leader is null, is not null then the other threads are executed take, put the thread into the condition queue.
If this time the leader is null, then: izt take the current thread A is the leader thread, and then execute the code (5) wait for delay
time - between (during which the thread releases the lock so other threads can offer additional element can also take blocking own)

The remaining time to expiration, the thread A competition will be re-acquire the lock, then reset leader thread nu ll, re-enter the circulation
loop, this time the team will find elements of the head has been through, it will directly return the head elements.
Before returning finally block will execute the code inside (7), Code (7) the execution result is true then the current line
after the process to remove expired elements from the queue, there are other threads into the operating team, this time calling conditions variable
singa l method, the activation condition waiting queue inside thread.

poll operation

Retrieves and removes the head-of expired elements, if not expired element null is returned

    public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E first = q.peek();
            //如果队列为空,或者不为空但是队头元素没有过期则返回 null
            if (first == null || first.getDelay(NANOSECONDS) > 0)
                return null;
            else
                return q.poll();
        } finally {
            lock.unlock();
        }
    }

size operation



    public int size() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.size();
        } finally {
            lock.unlock();
        }
    }

First, acquire an exclusive lock, and then call priority queue size method

demo


package com.ghgcn.thread.lesson07.concurrentqueue;

import java.util.Random;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * @author 刘楠
 * @since 2019/6/5
 */
public class DelayQueueTest01 {

    static  class DelayedEle implements Delayed{
        private final long delayTime ; //延迟时间
        private final long expire ; //到期时间
        private String taskName ; //任务名称

        public DelayedEle(long delay, String taskName) {
            this.delayTime = delay;

            this.taskName = taskName;
            this.expire  = System.currentTimeMillis() +delay;
        }


        /**
         * 剩余时间=到期时间 - 当前时间
         * @param unit
         * @return
         */
        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert( expire-System.currentTimeMillis(),TimeUnit.MILLISECONDS);
        }

        /**
         * 优先级队列里面的优先级规则
         * @param o
         * @return
         */
        @Override
        public int compareTo(Delayed o) {
          return (int) (this.getDelay(TimeUnit.MILLISECONDS)- o.getDelay(TimeUnit.MILLISECONDS));
        }


        @Override
        public String toString() {
            return "DelayedEle{" +
                    "delayTime=" + delayTime +
                    ", expire=" + expire +
                    ", taskName='" + taskName + '\'' +
                    '}';
        }
    }

    public static void main(String[] args) {
        //创建队列
        DelayQueue<DelayedEle> queue =new DelayQueue<DelayedEle>();

        ThreadLocalRandom random =ThreadLocalRandom.current();

        for(int i = 0; i<10; i++){
            DelayedEle ele = new DelayedEle(random.nextInt(1000),"task: "+i);
            queue.offer(ele);
        }

        //取出
        DelayedEle delayedEle=null;
        for(;;){
            try {
                while ((delayedEle=queue.take())!=null){
                    System.err.println(delayedEle.toString());
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }

        }
    }
}

  • result

DelayedEle {delayTime = 92, expire = 1559727104677, taskName = 'task: 8'}
DelayedEle {delayTime = 126, expire = 1559727104711, taskName = 'task: 3'}
DelayedEle {delayTime = 363, expire = 1559727104948, taskName = 'task 7 '}
DelayedEle {delayTime = 461, expire = 1559727105044, taskName =' task: 1 '}
DelayedEle {delayTime = 583, expire = 1559727105168, taskName =' task: 5 '}
DelayedEle {delayTime = 700, expire = 1559727105285, taskName = 'task: 4'}
DelayedEle {delayTime = 826, expire = 1559727105409, taskName = 'task: 0'}
DelayedEle {delayTime = 846, expire = 1559727105431, taskName = 'task: 9'}
DelayedEle {delayTime = 983, expire = 1559727105568, taskName = 'task: 6'}
DelayedEle delayTime = {999, expire = 1559727105584, taskName = 'task: 2'}

Create a task DelayedEle delay class, which represents the current task requires delayTime extended
much later than ms time expired, expire ms is the value of the current time plus the value of delayTime. In addition, to achieve the
Delayed interface enables a long getDelay (TimeUnit unit) is used to retrieve the current element is left much time expired, to achieve a relatively regular int compareTo (Delayed o) method is used to determine the priority queue elements.

DelayQueue PriorityQueue queue using its internal data storage, so
to achieve synchronization thread ReentrantLock. Further queue inside the elements to implement Delayed interfaces, one of which is
to get the current element to the interface to the expiration time remaining time, determines when dequeuing the element is expired, a is an element of
comparison between the interface because it is a priority the queue.
Here Insert Picture Description

Guess you like

Origin blog.csdn.net/ko0491/article/details/90905541