Use of DelayQueue in java

Use of DelayQueue in java

brief introduction

DelayQueue is a type of BlockingQueue, so it is thread safe. The feature of DelayQueue is that the data inserted into the Queue can be sorted by a custom delay time.Only elements with a delay time less than 0 can be removed.

DelayQueue

Let's first look at the definition of DelayQueue:

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

As you can see from the definition, all objects stored in DelayQueue must be subclasses of Delayed.

Delayed inherits from Comparable and needs to implement a getDelay method.

Why is it designed this way?

Because the underlying storage of DelayQueue is a PriorityQueue, as we mentioned in previous articles, PriorityQueue is a sortable Queue in which elements must implement the Comparable method.The getDelay method is used to determine if the sorted elements can be removed from the Queue.

Application of DelayQueue

DelayQueue is commonly used in the producer-consumer model, so let's take a specific example below.

To use DelayQueue first, you must customize a Delayed object:

[@Data](https://my.oschina.net/difrik)
public class DelayedUser implements Delayed {
    private String name;
    private long avaibleTime;

    public DelayedUser(String name, long delayTime){
        this.name=name;
        //avaibleTime =Current Time + delayTime
        this.avaibleTime=delayTime + System.currentTimeMillis();

    }

    [@Override](https://my.oschina.net/u/1162528)
    public long getDelay(TimeUnit unit) {
        //Determine if avaibleTime is greater than the current system time and convert the result to MILLISECONDS
        long diffTime= avaibleTime- System.currentTimeMillis();
        return unit.convert(diffTime,TimeUnit.MILLISECONDS);
    }

    [@Override](https://my.oschina.net/u/1162528)
    public int compareTo(Delayed o) {
        //CompeTo Used in DelayedUser Sorting
        return (int)(this.avaibleTime - ((DelayedUser) o).getAvaibleTime());
    }
}

In the above objects, we need to implement the getDelay and compareTo methods.

Next we create a producer:

[@Slf4j](https://my.oschina.net/slf4j)
[@Data](https://my.oschina.net/difrik)
@AllArgsConstructor
class DelayedQueueProducer implements Runnable {
    private DelayQueue<DelayedUser> delayQueue;

    private Integer messageCount;

    private long delayedTime;

    @Override
    public void run() {
        for (int i = 0; i < messageCount; i++) {
            try {
                DelayedUser delayedUser = new DelayedUser(
                        new Random().nextInt(1000)+"", delayedTime);
                log.info("put delayedUser {}",delayedUser);
                delayQueue.put(delayedUser);
                Thread.sleep(500);
            } catch (InterruptedException e) {
                log.error(e.getMessage(),e);
            }
        }
    }
}

In the producer, we create a new DelayedUser object every 0.5 seconds and incorporate it into the Queue.

Create another consumer:

@Slf4j
@Data
@AllArgsConstructor
public class DelayedQueueConsumer implements Runnable {

    private DelayQueue<DelayedUser> delayQueue;

    private int messageCount;

    @Override
    public void run() {
        for (int i = 0; i < messageCount; i++) {
            try {
                DelayedUser element = delayQueue.take();
                log.info("take {}",element );
            } catch (InterruptedException e) {
                log.error(e.getMessage(),e);
            }
        }
    }
}

In consumers, we loop through the queue to get objects.

Finally, take a look at an example of a call:

    @Test
    public void useDelayedQueue() throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(2);

        DelayQueue<DelayedUser> queue = new DelayQueue<>();
        int messageCount = 2;
        long delayTime = 500;
        DelayedQueueConsumer consumer = new DelayedQueueConsumer(
                queue, messageCount);
        DelayedQueueProducer producer = new DelayedQueueProducer(
                queue, messageCount, delayTime);

        // when
        executor.submit(producer);
        executor.submit(consumer);

        // then
        executor.awaitTermination(5, TimeUnit.SECONDS);
        executor.shutdown();

    }

In the test example above, we defined a pool of two threads where the producer generated two messages and the delayTime was set to 0.5 seconds, that is, after 0.5 seconds, the inserted object could be retrieved.

The thread pool will be closed after 5 seconds.

Run to see the results:

[pool-1-thread-1] INFO com.flydean.DelayedQueueProducer - put delayedUser DelayedUser(name=917, avaibleTime=1587623188389)
[pool-1-thread-2] INFO com.flydean.DelayedQueueConsumer - take DelayedUser(name=917, avaibleTime=1587623188389)
[pool-1-thread-1] INFO com.flydean.DelayedQueueProducer - put delayedUser DelayedUser(name=487, avaibleTime=1587623188899)
[pool-1-thread-2] INFO com.flydean.DelayedQueueConsumer - take DelayedUser(name=487, avaibleTime=1587623188899)

We see that the put and take of the message go on alternately and match our expectations.

If we make this change and change the delayTime to 50000, then the elements inserted before the thread pool closes will not expire, which means the consumer will not get the result.

summary

DelayQueue is a BlockingQueue with strange features that can be used when needed.

Examples of this article https://github.com/ddean2009/learn-java-collections

Welcome to my Public Number: program stuff, more exciting waiting for you! More please visit www.flydean.com

Tags: Programming Java less github

Posted on Tue, 05 May 2020 20:00:09 -0400 by vince251