Java 并发编程 - Delay(Delayed 概述、Delayed 实现、Delayed 使用、Delay 缓存实现、Delayed 延迟获取数据实现)

一、Delayed 概述

java 复制代码
public interface Delayed extends Comparable<Delayed> {

    long getDelay(TimeUnit unit);
}
  1. Delayed 用于表示在给定延迟时间之后应该被处理的对象

  2. 核心方法 getDelay 用于返回指定时间单位的剩余的延迟时间,正数表示延迟尚未到期,0 或负数表示延迟已到期

  3. Delay 继承了 Comparable<Delayed> 接口,需要同时实现 compareTo 方法

  4. 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、基本实现
  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;
        }
    }
}
  1. 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、缓存管理器
  1. 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);
    }
}
  1. 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、可重置缓存时间
  1. 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;
    }
}
  1. 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 延迟获取数据实现

  1. 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;
        }
    }
}
  1. 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 复制代码
# 输出结果

还未制作完成,等待中...
还未制作完成,等待中...
还未制作完成,等待中...
还未制作完成,等待中...
还未制作完成,等待中...
还未制作完成,等待中...
制作完成,获取到道具: 稿子
相关推荐
charlie11451419112 小时前
嵌入式现代C++教程: 构造函数优化:初始化列表 vs 成员赋值
开发语言·c++·笔记·学习·嵌入式·现代c++
wjs202412 小时前
Bootstrap5 消息弹窗
开发语言
资生算法程序员_畅想家_剑魔12 小时前
Kotlin常见技术分享-02-相对于Java 的核心优势-协程
java·开发语言·kotlin
ProgramHan12 小时前
Spring Boot 3.2 新特性:虚拟线程的落地实践
java·jvm·spring boot
IT=>小脑虎13 小时前
C++零基础衔接进阶知识点【详解版】
开发语言·c++·学习
nbsaas-boot13 小时前
Go vs Java 的三阶段切换路线图
java·开发语言·golang
码农小韩13 小时前
基于Linux的C++学习——指针
linux·开发语言·c++·学习·算法
微露清风13 小时前
系统性学习C++-第十九讲-unordered_map 和 unordered_set 的使用
开发语言·c++·学习
BBBBBAAAAAi13 小时前
Claude Code安装记录
开发语言·前端·javascript
毕设源码-钟学长13 小时前
【开题答辩全过程】以 基于Java的慕课点评网站为例,包含答辩的问题和答案
java·开发语言