Java geek

Related reading:

Java concurrent programming (A) knowledge map

Java concurrent programming atomicity Java concurrent programming visibility Java Concurrent programming Ordering Java Concurrent Programming Creating threads Overview Java Concurrent Programming Introduction (synchronized Java Concurrent Programming (8) Thread Life Cycle (9) Java Concurrent programming (9) Deadlock and deadlock bits Java concurrent programming (10) Java concurrent programming (10) Lock optimization Java Concurrent Programming introduction (11) Stream limiting scenarios and Spring Stream Limiting Scenarios (12) Producer and Consumer patterns – Java concurrent Programming Introduction (13) Read/write locks and cache templates Java Concurrent Programming Introduction (14) CountDownLatch application scenarios CyclicBarrier is an asynchronous task scheduling tool, with the CompleteFeature. You can use the CyclicBarrier to complete tasks. You can use the CyclicBarrier to complete tasks Introduction to Java Concurrent Programming Common Locking Scenarios and Locking Tools Introduction to Java Concurrent Programming Volatile keywords Introduction to Java Concurrent Programming 22 The ThreadLocal variable Daemon thread Introduction to Java Concurrent Programming (24) Java Atomic class


1. DelayQueue is introduced

Let’s look at the class structure:

1. The object placed in the DelayQueue must implement the Delayed interface

2. The getDelay method of the Delayed interface is implemented to return the Delayed time, and the objects placed in the DelayQueue can be retrieved from the queue only after this time is exceeded, thus achieving the Delayed effect.

3. Determine which object to fetch first from the queue by implementing the Comparable interface, usually according to the result of the getDelay method, so that the object with the shortest delay can be fetched first.

2. Application scenario

For the application scenario of DelayQueue, it is important to understand that delay and invalidation may be two different concepts in a particular scenario. Delay is the amount of time delayed before execution, while invalidation is not necessarily the same as delay. For example, if the cache is not used, the invalidation time is 2 minutes, after 2 minutes the cache is cleared, but the cache is used before invalidation. This failure time will be extended. See below:

Once an object is placed in a DelayQueue, it is not reordered until the element is removed and replaced, and a DelayQueue is a blocking priority queue, the first element is not retrieved, and the next element is not retrieved, and if the delay of the last element is changed, reduced, but there is no reordering, DelayQueue is not suitable for scenarios where element latency changes dynamically, such as caching, idle database connection pools, etc., all of which have longer inefficiencies due to use.

Of course, it’s possible to reorder elements by removing them and putting them back in the DelayQueue, but you don’t usually do this because it’s too expensive to reorder the queue every time cached elements are used. Therefore, cache and idle resource pools are usually cleared by a scheduled thread that traverses all elements to determine whether the invalidity time has been exceeded.

3. DelayQueue example

Implement delayed execution of tasks.

import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; Public class DelayQueueDemo {private static class Task implements Delayed {private String name; private long start; private long delayMillis; Task(String name, long delayMillis) { this.name = name; this.delayMillis = delayMillis; start = System.currentTimeMillis(); } @Override public long getDelay(TimeUnit unit) { long result = unit.convert((start + delayMillis) - System.currentTimeMillis(),TimeUnit.MILLISECONDS); return result; } @Override public int compareTo(Delayed o) { return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS)); } public void exec() { System.out.println(name + " was called."); } } private static class TaskTimer implements Runnable { private static volatile TaskTimer instance; DelayQueue<Task> delayQueue = new DelayQueue(); private TaskTimer() {} public static TaskTimer getInstance() { if (instance == null) { synchronized (TaskTimer.class) { if (instance == null) { instance = new TaskTimer(); } } } return instance; } public void add(Task task) { delayQueue.put(task); } @Override public void run() { while (true) { try { Task task = delayQueue.take(); // Block the queue and fetch the task from the head of the queue task.exec(); } catch(InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws Exception { TaskTimer taskTimer = TaskTimer.getInstance(); new Thread(taskTimer).start(); addTask("task1", 3000); addTask("task2", 1500); } private static void addTask(String taskName, long delayMillis) { Task task = new Task(taskName, delayMillis); TaskTimer.getInstance().add(task); }}Copy the code

Log printing:

task2 was called.
task1 was called.
Copy the code

Task2 is executed after 1.5 seconds, and task1 is executed after 3 seconds.

4. Summary

1.DelayQueue is a blocking priority queue.

DelayQueue elements are ordered when they are enqueued. Even if the return value of the getDelay method changes after they are enqueued, the elements are not reordered unless they are re-enqueued. Therefore, it is not suitable for scenarios where the delay time changes dynamically, such as cache release or idle connection pool release.

3. You can consider using DelayQueue to implement the traffic limiting scenario. When too many requests are processed, part of the requests can be put into the DelayQueue and retrieved for execution after a period of time.

4. The open source timer can also achieve the effect of delayed execution of tasks, while the DelayQueue is lighter and can be used according to the actual situation.


<– read left mark, left point like!