Java中的延时队列是一种特殊的数据结构,它允许我们在指定的时间后才处理队列中的元素。常见的场景包括任务调度、定时消息发送、限流等。下面将总结几种常见的延时队列实现方案,并提供代码示例。
1. 基于java.util.concurrent.PriorityBlockingQueue
的实现
PriorityBlockingQueue
是Java提供的一个线程安全的优先级队列。在实现延时队列时,我们可以将任务的执行时间作为优先级进行管理。
import java.util.concurrent.*;
import java.util.Date;
class DelayedTask implements Delayed {
private final long delay;
private final long trigger;
private final String name;
public DelayedTask(long delay, String name) {
this.delay = delay;
this.trigger = System.currentTimeMillis() + delay;
this.name = name;
}
@Override
public long getDelay(TimeUnit unit) {
long diff = trigger - System.currentTimeMillis();
return unit.convert(diff, TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
if (this.trigger < ((DelayedTask) o).trigger) {
return -1;
}
if (this.trigger > ((DelayedTask) o).trigger) {
return 1;
}
return 0;
}
public void run() {
System.out.println("Executing task: " + name + " at " + new Date());
}
}
public class DelayQueueExample {
public static void main(String[] args) throws InterruptedException {
DelayQueue<DelayedTask> queue = new DelayQueue<>();
queue.put(new DelayedTask(3000, "Task 1"));
queue.put(new DelayedTask(1000, "Task 2"));
queue.put(new DelayedTask(2000, "Task 3"));
while (!queue.isEmpty()) {
DelayedTask task = queue.take();
task.run();
}
}
}
在这个示例中,我们定义了一个 DelayedTask
类,它实现了 Delayed
接口,并重写了 getDelay
和 compareTo
方法。在 main
方法中,我们创建了一个 DelayQueue
,将不同延迟的任务放入队列中,并依次执行。
2. 基于ScheduledExecutorService
的实现
ScheduledExecutorService
是 Java 提供的另一个方法来实现延时任务。它更适合用来处理定时和周期性任务。
import java.util.concurrent.*;
public class ScheduledExecutorExample {
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable task1 = () -> System.out.println("Task 1 executed at: " + new Date());
Runnable task2 = () -> System.out.println("Task 2 executed at: " + new Date());
// 延迟1秒执行
scheduler.schedule(task1, 1, TimeUnit.SECONDS);
// 延迟2秒执行
scheduler.schedule(task2, 2, TimeUnit.SECONDS);
scheduler.shutdown();
}
}
在这个示例中,我们创建了一个 ScheduledExecutorService
实例,并使用 schedule
方法定义了延迟执行的任务。每个任务都会在指定的延迟后执行。
3. 自定义线程与时间轮算法
对于特定的高性能场景,可能需要自定义实现延时队列的逻辑,比如使用时间轮算法。这种方式比较复杂,但在某些场合下可以提高效率。
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class TimeWheel {
// 时间轮的槽数量
private final int wheelSize;
private final ConcurrentHashMap<Long, Runnable> tasks = new ConcurrentHashMap<>();
public TimeWheel(int wheelSize) {
this.wheelSize = wheelSize;
}
public void addTask(long delay, Runnable task) {
long executionTime = System.currentTimeMillis() + delay;
tasks.put(executionTime, task);
}
public void start() {
new Thread(() -> {
while (true) {
long currentTime = System.currentTimeMillis();
tasks.forEach((time, task) -> {
if (time <= currentTime) {
task.run();
tasks.remove(time);
}
});
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
}
}
public class TimeWheelExample {
public static void main(String[] args) {
TimeWheel timeWheel = new TimeWheel(10);
timeWheel.addTask(2000, () -> System.out.println("Task 1 executed at: " + new Date()));
timeWheel.addTask(3000, () -> System.out.println("Task 2 executed at: " + new Date()));
timeWheel.start();
}
}
在这个示例中,我们实现了一个简单的时间轮,该轮会周期性检查任务并执行到期的任务。
总结
Java中有多种实现延时队列的方式,包括使用 DelayQueue
、ScheduledExecutorService
,以及自定义的时间轮算法。选择哪种实现方案取决于具体的业务需求和性能考虑。每种实现都有其适用场景,可以根据实际情况选择最优方案。