本文目录导读:

- 使用 ScheduledExecutorService(推荐)
- 使用 Timer / TimerTask(简单场景)
- 使用 DelayQueue(任务调度)
- 复杂系统:使用 Redis 实现分布式延时任务
- 完整业务系统示例
- 使用建议
- 关键要点
我来详细介绍Java中实现延时任务的几种常见方式,并提供完整案例。
使用 ScheduledExecutorService(推荐)
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class ScheduledExecutorDemo {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
private final ScheduledExecutorService scheduler;
private final AtomicInteger taskCounter = new AtomicInteger(0);
public ScheduledExecutorDemo(int poolSize) {
// 创建线程池
this.scheduler = Executors.newScheduledThreadPool(poolSize, runnable -> {
Thread thread = new Thread(runnable, "Scheduled-Task-Thread");
thread.setDaemon(true);
return thread;
});
}
// 单个延时任务
public void scheduleDelayedTask(Runnable task, long delay, TimeUnit unit) {
System.out.println("[" + now() + "] 任务已安排,将在 " + delay + " " + unit + " 后执行");
scheduler.schedule(() -> {
try {
System.out.println("[" + now() + "] 开始执行任务 #" +
taskCounter.incrementAndGet());
task.run();
} catch (Exception e) {
System.err.println("任务执行失败: " + e.getMessage());
}
}, delay, unit);
}
// 固定频率执行
public void scheduleAtFixedRate(Runnable task, long initialDelay,
long period, TimeUnit unit) {
scheduler.scheduleAtFixedRate(task, initialDelay, period, unit);
}
// 固定延迟执行(上次执行完后延迟)
public void scheduleWithFixedDelay(Runnable task, long initialDelay,
long delay, TimeUnit unit) {
scheduler.scheduleWithFixedDelay(task, initialDelay, delay, unit);
}
// 关闭任务
public void shutdown() {
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
}
private String now() {
return LocalDateTime.now().format(FORMATTER);
}
// 测试
public static void main(String[] args) throws InterruptedException {
ScheduledExecutorDemo demo = new ScheduledExecutorDemo(3);
// 单次延时任务
demo.scheduleDelayedTask(() ->
System.out.println("[" + demo.now() + "] 这是一次性延时任务"),
3, TimeUnit.SECONDS);
// 延迟2秒后,每5秒执行一次
demo.scheduleAtFixedRate(() ->
System.out.println("[" + demo.now() + "] 固定频率任务"),
2, 5, TimeUnit.SECONDS);
// 延迟1秒后,每次执行完延迟3秒
demo.scheduleWithFixedDelay(() -> {
System.out.println("[" + demo.now() + "] 固定延迟任务开始");
try {
Thread.sleep(1000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}, 1, 3, TimeUnit.SECONDS);
Thread.sleep(20000);
demo.shutdown();
}
}
使用 Timer / TimerTask(简单场景)
import java.util.Timer;
import java.util.TimerTask;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class TimerDemo {
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("HH:mm:ss");
public static void main(String[] args) throws InterruptedException {
Timer timer = new Timer("Timer-Thread", true); // daemon线程
// 单次延时任务
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("[" + now() + "] 单次延时任务执行");
}
}, 3000); // 3秒后执行
// 固定延迟执行
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println("[" + now() + "] 定时任务执行");
}
}, 2000, 5000); // 2秒后开始,每5秒执行一次
Thread.sleep(15000);
timer.cancel();
}
private static String now() {
return LocalDateTime.now().format(FORMATTER);
}
}
使用 DelayQueue(任务调度)
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
// 延时任务类
class DelayedTask implements Delayed {
private final String taskName;
private final long executeTime; // 执行时间戳
private final Runnable task;
public DelayedTask(String taskName, Runnable task, long delay, TimeUnit unit) {
this.taskName = taskName;
this.task = task;
this.executeTime = System.currentTimeMillis() +
TimeUnit.MILLISECONDS.convert(delay, unit);
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(executeTime - System.currentTimeMillis(),
TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed other) {
return Long.compare(this.executeTime,
((DelayedTask) other).executeTime);
}
public void execute() {
task.run();
}
public String getTaskName() {
return taskName;
}
}
public class DelayQueueDemo {
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("HH:mm:ss");
private final DelayQueue<DelayedTask> taskQueue = new DelayQueue<>();
private static final AtomicInteger taskCounter = new AtomicInteger(0);
public void startWorker() {
Thread worker = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
DelayedTask task = taskQueue.take();
System.out.println("[" + now() + "] 执行任务: " +
task.getTaskName());
task.execute();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}, "DelayQueue-Worker");
worker.setDaemon(true);
worker.start();
}
public void addTask(String name, Runnable task, long delay, TimeUnit unit) {
DelayedTask delayedTask = new DelayedTask(
name, task, delay, unit);
taskQueue.put(delayedTask);
System.out.println("[" + now() + "] 已添加任务: " + name +
", 延迟: " + delay + " " + unit);
}
private String now() {
return LocalDateTime.now().format(FORMATTER);
}
public static void main(String[] args) throws InterruptedException {
DelayQueueDemo demo = new DelayQueueDemo();
demo.startWorker();
// 添加不同延迟的任务
demo.addTask("任务A", () ->
System.out.println("[" + demo.now() + "] 任务A执行完成"),
3, TimeUnit.SECONDS);
demo.addTask("任务B", () ->
System.out.println("[" + demo.now() + "] 任务B执行完成"),
1, TimeUnit.SECONDS);
demo.addTask("任务C", () ->
System.out.println("[" + demo.now() + "] 任务C执行完成"),
5, TimeUnit.SECONDS);
Thread.sleep(8000);
}
}
复杂系统:使用 Redis 实现分布式延时任务
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Set;
import java.util.UUID;
public class RedisDelayedTask {
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("HH:mm:ss");
private final JedisPool jedisPool;
private final String taskQueueKey;
public RedisDelayedTask(String redisHost, int redisPort, String queueName) {
this.jedisPool = new JedisPool(redisHost, redisPort);
this.taskQueueKey = queueName;
}
// 添加延时任务
public void addDelayedTask(String taskId, int delaySeconds, String data) {
try (Jedis jedis = jedisPool.getResource()) {
long delayTimestamp = System.currentTimeMillis() / 1000 + delaySeconds;
jedis.zadd(taskQueueKey, delayTimestamp,
String.format("%s:%s", taskId, data));
System.out.println("[" + now() + "] 添加任务: " + taskId +
", 将在 " + delaySeconds + " 秒后执行");
}
}
// 获取到期任务
public Set<String> getDueTasks() {
try (Jedis jedis = jedisPool.getResource()) {
long currentTimestamp = System.currentTimeMillis() / 1000;
return jedis.zrangeByScore(taskQueueKey, 0, currentTimestamp);
}
}
// 清除已处理任务
public void removeTask(String task) {
try (Jedis jedis = jedisPool.getResource()) {
jedis.zrem(taskQueueKey, task);
}
}
// 启动扫描器
public void startScanner() {
Thread scanner = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
Set<String> dueTasks = getDueTasks();
for (String task : dueTasks) {
processTask(task);
removeTask(task);
}
Thread.sleep(1000); // 每秒检查一次
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
} catch (Exception e) {
System.err.println("处理任务时出错: " + e.getMessage());
}
}
}, "Redis-Task-Scanner");
scanner.setDaemon(true);
scanner.start();
}
private void processTask(String task) {
System.out.println("[" + now() + "] 执行延时任务: " + task);
// 在这里执行实际的业务逻辑
}
private String now() {
return LocalDateTime.now().format(FORMATTER);
}
public static void main(String[] args) throws InterruptedException {
// 假设Redis在本地运行
RedisDelayedTask demo = new RedisDelayedTask("localhost", 6379, "delayed:tasks");
// 启动扫描器
demo.startScanner();
// 添加不同延迟的任务
for (int i = 1; i <= 5; i++) {
String taskId = UUID.randomUUID().toString().substring(0, 8);
demo.addDelayedTask(taskId, i * 2, "任务数据-" + i);
}
Thread.sleep(15000);
}
// 清理
public void shutdown() {
jedisPool.close();
}
}
完整业务系统示例
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
public class OrderCancelSystem {
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private final ScheduledExecutorService scheduler;
private final ExecutorService taskExecutor;
private final ConcurrentMap<String, ScheduledFuture<?>> taskMap;
private final AtomicLong orderCounter;
public OrderCancelSystem() {
this.scheduler = Executors.newScheduledThreadPool(2);
this.taskExecutor = Executors.newFixedThreadPool(5);
this.taskMap = new ConcurrentHashMap<>();
this.orderCounter = new AtomicLong(0);
}
// 创建订单并设置超时自动取消
public String createOrder(String productId, int quantity,
long timeoutSeconds) {
String orderId = "ORDER" +
String.format("%06d", orderCounter.incrementAndGet());
System.out.println("[" + now() + "] 创建订单: " + orderId +
", 商品: " + productId + ", " +
timeoutSeconds + "秒后未支付将自动取消");
// 安排过期检测
OrderCancelTask cancelTask = new OrderCancelTask(orderId);
ScheduledFuture<?> future = scheduler.schedule(cancelTask,
timeoutSeconds, TimeUnit.SECONDS);
// 存储映射关系,以便后续可能的取消
taskMap.put(orderId, future);
return orderId;
}
// 取消定时任务(订单已支付)
public void cancelTask(String orderId) {
ScheduledFuture<?> future = taskMap.remove(orderId);
if (future != null) {
future.cancel(false);
System.out.println("[" + now() + "] 订单 " + orderId +
" 已支付,取消自动关闭");
}
}
// 关闭系统
public void shutdown() {
scheduler.shutdownNow();
taskExecutor.shutdownNow();
System.out.println("[" + now() + "] 系统已关闭");
}
private String now() {
return LocalDateTime.now().format(FORMATTER);
}
private class OrderCancelTask implements Runnable {
private final String orderId;
public OrderCancelTask(String orderId) {
this.orderId = orderId;
}
@Override
public void run() {
taskMap.remove(orderId); // 清理映射
// 使用线程池异步执行取消逻辑
taskExecutor.submit(() -> {
System.out.println("[" + now() + "] 订单 " + orderId +
" 超时未支付,已自动取消");
// 模拟取消操作
try {
Thread.sleep(500);
System.out.println("[" + now() + "] 订单 " + orderId +
" 取消操作完成,库存已恢复");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
}
public static void main(String[] args) throws InterruptedException {
OrderCancelSystem system = new OrderCancelSystem();
// 创建订单,5秒后自动取消
String order1 = system.createOrder("商品A", 2, 5);
String order2 = system.createOrder("商品B", 1, 8);
Thread.sleep(3000);
// 用户支付了第一个订单
System.out.println("[" + system.now() + "] 用户支付订单 " + order1);
system.cancelTask(order1);
Thread.sleep(10000);
// 创建更多订单测试
String order3 = system.createOrder("商品C", 3, 2);
Thread.sleep(5000);
system.shutdown();
}
}
使用建议
| 场景 | 推荐方案 | 优势 |
|---|---|---|
| 单机应用 | ScheduledExecutorService | 灵活、高效、线程池管理 |
| 简单任务调度 | Timer/TimerTask | 简单易用 |
| 内存级延迟队列 | DelayQueue | 支持复杂排序 |
| 分布式系统 | Redis ZSet | 支持集群、持久化 |
| 企业级调度 | Quartz | 功能强大、支持CRON表达式 |
关键要点
- 线程安全性:确保任务线程安全
- 异常处理:捕获并处理任务异常
- 资源管理:及时关闭线程池
- 优雅关闭:使用shutdown/shutdownNow方法
- 监控告警:添加日志和监控机制
根据实际需求选择合适的方案,注意考虑性能和并发需求。