DelayQueue delay queue

Posted by erwt on Wed, 15 Dec 2021 00:12:19 +0100

DelayQueue is a class that implements the BlockingQueue interface. It is also a blocking queue, but it also has some unique functions, that is, when obtaining elements, it is necessary to detect whether the elements reach the delay time. If the delay time is not reached, the elements cannot be obtained.

The elements in the queue need to implement the Delay interface. This interface has a method getDelay. When this method returns 0 or a negative number, it indicates that the element has reached the Delay time and can be obtained normally when obtaining the element, otherwise it cannot be obtained. The Delay interface inherits the Comparable interface and rewrites its compareTo method to sort the elements in the queue. It is usually sorted according to the small arrival time. It is used to avoid that the previous elements do not arrive and the Delay time cannot be taken out, resulting in the failure to obtain the subsequent elements.

java delay queue provides the function of obtaining queue elements at a specified time. The queue header element is the element closest to expiration. If there is no expired element, the poll() method will return null value. The timeout is determined by the return value of getDelay(TimeUnit.NANOSECONDS) method is less than or equal to 0. Delay queues cannot hold empty elements.

   

public interface Delayed extends Comparable<Delayed> {

    /**
     * Returns the remaining delay associated with this object, in the
     * given time unit.
     *
     * @param unit the time unit
     * @return the remaining delay; zero or negative values indicate
     * that the delay has already elapsed
     */
    long getDelay(TimeUnit unit);
}

It can be seen from the Delayed definition that queue elements need to implement getDelay(TimeUnit unit) method and compareTo(Delayed o) method. getDelay defines the remaining expiration time, and compareTo method defines the element sorting rules. Note that the sorting rules of elements affect the acquisition order of elements.

Get element: non blocking

 public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E first = q.peek();
            if (first == null || first.getDelay(NANOSECONDS) > 0)
                return null;
            else
                return q.poll();
        } finally {
            lock.unlock();
        }
    }

Get element: blocking

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                E first = q.peek();
                if (first == null)
                    available.await();
                else {
                    long delay = first.getDelay(NANOSECONDS);
                    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();
        }
    }

Test:

package com.tech.netty.test;

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * @author lw
 * @since 2021/9/6
 */
public class Item implements Delayed {

    private int num;
    private long time;

    public Item(int num, long delay) {
        this.num = num;
        this.time = delay+System.currentTimeMillis();
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return time-System.currentTimeMillis();
    }
    
    //The settings are arranged according to the delay time from small to large
    @Override
    public int compareTo(Delayed o) {
        Item o1 = (Item) o;
        long diff=time-o1.time;
        if(diff<=0){
            return -1;
        }else{
            return 1;
        }
    }

    @Override
    public String toString() {
        return "Item{" +
                "num=" + num +
                ", time=" + time +
                '}';
    }
}
package com.tech.netty.test;

import java.util.concurrent.DelayQueue;

/**
 * @author lw
 * @since 2021/9/6
 */
public class DQueue {
    public static void main(String[] args) throws InterruptedException {
        DelayQueue<Item> delayQueue=new DelayQueue<Item>();
        Item item1 = new Item(1, 3000);
        Item item2 = new Item(2, 6000);
        Item item3= new Item(3, 9000);
        delayQueue.add(item2);
        delayQueue.add(item1);
        delayQueue.add(item3);
        int size = delayQueue.size();
        for (int i = 0; i <size ; i++) {
            System.out.println(delayQueue.take());
        }
    }
}
It can be found that the elements are output in ascending order of delay time every 3 seconds

If you set the elements to be arranged according to the expiration time from large to small, you will find that the elements are arranged in reverse order according to the delay time and output almost at the same time.

Topics: Java thread