一、Delayed 概述
java
public interface Delayed extends Comparable<Delayed> {
long getDelay(TimeUnit unit);
}
-
Delayed 用于表示在给定延迟时间之后应该被处理的对象
-
核心方法 getDelay 用于返回指定时间单位的剩余的延迟时间,正数表示延迟尚未到期,0 或负数表示延迟已到期
-
Delay 继承了
Comparable<Delayed>接口,需要同时实现 compareTo 方法 -
Delayed 通常与 DelayQueue 结合使用
二、Delayed 实现
- MyDelayedTask.java
java
public class MyDelayedTask implements Delayed {
private final long baseTime; // 基准时间,通常为创建时间
private final long delay; // 延迟时长
private final TimeUnit unit; // 时间单位
public MyDelayedTask(long delay, TimeUnit unit) {
this.baseTime = System.nanoTime();
this.delay = delay;
this.unit = unit;
}
@Override
public long getDelay(TimeUnit requestedUnit) {
// 计算已经过去的时间
long elapsed = System.nanoTime() - baseTime;
// 计算总延迟的纳秒数
long totalDelayNanos = unit.toNanos(delay);
// 计算剩余延迟
long remaining = totalDelayNanos - elapsed;
// 转换为请求的时间单位
return requestedUnit.convert(remaining, TimeUnit.NANOSECONDS);
}
@Override
public int compareTo(Delayed other) {
// 统一转换为纳秒进行比较
long myDelay = this.getDelay(TimeUnit.NANOSECONDS);
long otherDelay = other.getDelay(TimeUnit.NANOSECONDS);
return Long.compare(myDelay, otherDelay);
}
}
- SimpleDelayedTask.java
java
public class SimpleDelayedTask implements Delayed {
private final String data;
private final long startTime;
private final long delayNanos;
public SimpleDelayedTask(String data, long delay, TimeUnit unit) {
this.data = data;
this.startTime = System.nanoTime();
this.delayNanos = unit.toNanos(delay);
}
@Override
public long getDelay(TimeUnit unit) {
// 计算过去的延迟时间
long elapsed = System.nanoTime() - startTime;
// 计算剩余的延迟时间
long remaining = delayNanos - elapsed;
// 转换为指定的时间单位
return unit.convert(remaining, TimeUnit.NANOSECONDS);
}
@Override
public int compareTo(Delayed other) {
if (this == other) return 0;
// 统一转换为纳秒进行比较
long thisDelay = this.getDelay(TimeUnit.NANOSECONDS);
long otherDelay = other.getDelay(TimeUnit.NANOSECONDS);
return Long.compare(thisDelay, otherDelay);
}
public String getData() {
long delay = this.getDelay(TimeUnit.NANOSECONDS);
if (delay <= 0) {
return data;
} else {
return null;
}
}
}
三、Delayed 使用
1、基本使用
java
SimpleDelayedTask simpleDelayedTask = new SimpleDelayedTask("test content", 3, TimeUnit.SECONDS);
while (true) {
String data = simpleDelayedTask.getData();
if (data != null) {
System.out.println("任务就绪,执行任务,获取到数据: " + data);
break;
} else {
System.out.println("任务还未就绪,等待中...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
# 输出结果
任务还未就绪,等待中...
任务还未就绪,等待中...
任务还未就绪,等待中...
任务还未就绪,等待中...
任务还未就绪,等待中...
任务还未就绪,等待中...
任务就绪,执行任务,获取到数据: test content
java
SimpleDelayedTask task1 = new SimpleDelayedTask("task1", 2, TimeUnit.SECONDS);
SimpleDelayedTask task2 = new SimpleDelayedTask("task2", 4, TimeUnit.SECONDS);
SimpleDelayedTask task3 = new SimpleDelayedTask("task3", 1, TimeUnit.SECONDS);
boolean task1Done = false;
boolean task2Done = false;
boolean task3Done = false;
while (!task1Done || !task2Done || !task3Done) {
if (!task1Done) {
String data = task1.getData();
if (data != null) {
System.out.println("任务 1 完成: " + data);
task1Done = true;
}
}
if (!task2Done) {
String data = task2.getData();
if (data != null) {
System.out.println("任务 2 完成: " + data);
task2Done = true;
}
}
if (!task3Done) {
String data = task3.getData();
if (data != null) {
System.out.println("任务 3 完成: " + data);
task3Done = true;
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("所有任务完成");
# 输出结果
任务 3 完成: task3
任务 1 完成: task1
任务 2 完成: task2
所有任务完成
2、结合 DelayQueue 使用
java
DelayQueue<SimpleDelayedTask> delayQueue = new DelayQueue<>();
delayQueue.add(new SimpleDelayedTask("test content1", 2, TimeUnit.SECONDS));
delayQueue.add(new SimpleDelayedTask("test content2", 4, TimeUnit.SECONDS));
delayQueue.add(new SimpleDelayedTask("test content3", 1, TimeUnit.SECONDS));
while (!delayQueue.isEmpty()) {
try {
SimpleDelayedTask simpleDelayedTask = delayQueue.take();
System.out.println("任务就绪,执行任务,获取到数据: " + simpleDelayedTask.getData());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
# 输出结果
任务就绪,执行任务,获取到数据: test content3
任务就绪,执行任务,获取到数据: test content1
任务就绪,执行任务,获取到数据: test content2
四、Delay 缓存实现
1、基本实现
- Delayed 实现,CacheItem.java
java
public class CacheItem implements Delayed {
private final String data;
private final long startTime;
private final long delayNanos;
public CacheItem(String data, long delay, TimeUnit unit) {
this.data = data;
this.startTime = System.nanoTime();
this.delayNanos = unit.toNanos(delay);
}
@Override
public long getDelay(TimeUnit unit) {
long elapsed = System.nanoTime() - startTime;
long remaining = delayNanos - elapsed;
return unit.convert(remaining, TimeUnit.NANOSECONDS);
}
@Override
public int compareTo(Delayed other) {
if (this == other) return 0;
// 统一转换为纳秒进行比较
long thisDelay = this.getDelay(TimeUnit.NANOSECONDS);
long otherDelay = other.getDelay(TimeUnit.NANOSECONDS);
return Long.compare(thisDelay, otherDelay);
}
public String getData() {
long delay = this.getDelay(TimeUnit.NANOSECONDS);
if (delay <= 0) {
return null;
} else {
return data;
}
}
}
- Test
java
CacheItem cacheItem = new CacheItem("test content", 3, TimeUnit.SECONDS);
while (true) {
String data = cacheItem.getData();
if (data != null) {
System.out.println("缓存未过期,获取到数据: " + data);
} else {
System.out.println("缓存已过期");
break;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
# 输出结果
缓存未过期,获取到数据: test content
缓存未过期,获取到数据: test content
缓存未过期,获取到数据: test content
缓存未过期,获取到数据: test content
缓存未过期,获取到数据: test content
缓存未过期,获取到数据: test content
缓存已过期
2、缓存管理器
- SimpleCacheManager.java
java
public class SimpleCacheManager {
private final Map<String, CacheItem> cacheItemMap = new ConcurrentHashMap<>();
public void put(String key, String value, long ttl, TimeUnit unit) {
cacheItemMap.put(key, new CacheItem(value, ttl, unit));
System.out.println("缓存设置: " + key + " -> " + value + " (TTL: " + ttl + " " + unit + ")");
}
public void remove(String key) {
cacheItemMap.remove(key);
System.out.println("缓存移除: " + key);
}
public String get(String key) {
CacheItem item = cacheItemMap.get(key);
if (item != null) {
return item.getData();
}
return null;
}
public void clean() {
cacheItemMap.values().removeIf(item -> item.getDelay(TimeUnit.NANOSECONDS) <= 0);
}
}
- Test
java
SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
simpleCacheManager.put("user:A", "用户 A 信息", 3, TimeUnit.SECONDS);
simpleCacheManager.put("config:app", "应用配置", 5, TimeUnit.SECONDS);
for (int i = 0; i < 8; i++) {
System.out.println("=== 第 " + (i + 1) + " 次查询 ===");
String userData = simpleCacheManager.get("user:A");
System.out.println("user:A -> " + userData);
String configData = simpleCacheManager.get("config:app");
System.out.println("config:app -> " + configData);
simpleCacheManager.clean();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
# 输出结果
缓存设置: user:A -> 用户 A 信息 (TTL: 3 SECONDS)
缓存设置: config:app -> 应用配置 (TTL: 5 SECONDS)
=== 第 1 次查询 ===
user:A -> 用户 A 信息
config:app -> 应用配置
=== 第 2 次查询 ===
user:A -> 用户 A 信息
config:app -> 应用配置
=== 第 3 次查询 ===
user:A -> 用户 A 信息
config:app -> 应用配置
=== 第 4 次查询 ===
user:A -> null
config:app -> 应用配置
=== 第 5 次查询 ===
user:A -> null
config:app -> 应用配置
=== 第 6 次查询 ===
user:A -> null
config:app -> null
=== 第 7 次查询 ===
user:A -> null
config:app -> null
=== 第 8 次查询 ===
user:A -> null
config:app -> null
3、可重置缓存时间
- Delayed 实现,MyCacheItem.java
java
public class MyCacheItem implements Delayed {
private final String data;
private long startTime;
private long delayNanos;
public MyCacheItem(String data, long delay, TimeUnit unit) {
this.data = data;
this.startTime = System.nanoTime();
this.delayNanos = unit.toNanos(delay);
}
@Override
public long getDelay(TimeUnit unit) {
long elapsed = System.nanoTime() - startTime;
long remaining = delayNanos - elapsed;
return unit.convert(remaining, TimeUnit.NANOSECONDS);
}
@Override
public int compareTo(Delayed other) {
if (this == other) return 0;
// 统一转换为纳秒进行比较
long thisDelay = this.getDelay(TimeUnit.NANOSECONDS);
long otherDelay = other.getDelay(TimeUnit.NANOSECONDS);
return Long.compare(thisDelay, otherDelay);
}
public String getData() {
long delay = this.getDelay(TimeUnit.NANOSECONDS);
if (delay <= 0) {
return null;
} else {
return data;
}
}
public boolean resetDelay(long delay, TimeUnit unit) {
if (getDelay(TimeUnit.NANOSECONDS) <= 0) {
return false;
}
// 重置缓存时间
this.startTime = System.nanoTime();
this.delayNanos = unit.toNanos(delay);
return true;
}
}
- Test
java
MyCacheItem myCacheItem = new MyCacheItem("test content", 3, TimeUnit.SECONDS);
int queryCount = 0;
while (true) {
// 在第 3 次查询时,重置缓存过期时间为 5 秒
queryCount++;
System.out.println("=== 第 " + (queryCount) + " 次查询 ===");
if (queryCount == 3) {
System.out.println("重置缓存过期时间为 5 秒");
myCacheItem.resetDelay(5, TimeUnit.SECONDS);
}
String data = myCacheItem.getData();
if (data != null) {
System.out.println("缓存未过期,获取到数据: " + data);
} else {
System.out.println("缓存已过期");
break;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
java
# 输出结果
=== 第 1 次查询 ===
缓存未过期,获取到数据: test content
=== 第 2 次查询 ===
缓存未过期,获取到数据: test content
=== 第 3 次查询 ===
重置缓存过期时间为 5 秒
缓存未过期,获取到数据: test content
=== 第 4 次查询 ===
缓存未过期,获取到数据: test content
=== 第 5 次查询 ===
缓存未过期,获取到数据: test content
=== 第 6 次查询 ===
缓存未过期,获取到数据: test content
=== 第 7 次查询 ===
缓存未过期,获取到数据: test content
=== 第 8 次查询 ===
缓存未过期,获取到数据: test content
=== 第 9 次查询 ===
缓存未过期,获取到数据: test content
=== 第 10 次查询 ===
缓存未过期,获取到数据: test content
=== 第 11 次查询 ===
缓存未过期,获取到数据: test content
=== 第 12 次查询 ===
缓存未过期,获取到数据: test content
=== 第 13 次查询 ===
缓存已过期
五、Delayed 延迟获取数据实现
- Delayed 实现,MakeTask.java
java
public class MakeTask implements Delayed {
private final String data;
private final long startTime;
private final long delayNanos;
public MakeTask(String data, long delay, TimeUnit unit) {
this.data = data;
this.startTime = System.nanoTime();
this.delayNanos = unit.toNanos(delay);
}
@Override
public long getDelay(TimeUnit unit) {
long elapsed = System.nanoTime() - startTime;
long remaining = delayNanos - elapsed;
return unit.convert(remaining, TimeUnit.NANOSECONDS);
}
@Override
public int compareTo(Delayed other) {
if (this == other) return 0;
// 统一转换为纳秒进行比较
long thisDelay = this.getDelay(TimeUnit.NANOSECONDS);
long otherDelay = other.getDelay(TimeUnit.NANOSECONDS);
return Long.compare(thisDelay, otherDelay);
}
public String getData() {
long delay = this.getDelay(TimeUnit.NANOSECONDS);
if (delay <= 0) {
return data;
} else {
return null;
}
}
}
- Test
java
MakeTask makeTask = new MakeTask("稿子", 3, TimeUnit.SECONDS);
while (true) {
String data = makeTask.getData();
if (data != null) {
System.out.println("制作完成,获取到道具: " + data);
break;
} else {
System.out.println("还未制作完成,等待中...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
java
# 输出结果
还未制作完成,等待中...
还未制作完成,等待中...
还未制作完成,等待中...
还未制作完成,等待中...
还未制作完成,等待中...
还未制作完成,等待中...
制作完成,获取到道具: 稿子