java使用看门狗原理实现监听业务

看门狗是一种定时器电路,常用于单片机复位,也可应用于Java程序中实现业务逻辑监控。其原理是定时器在等待外部触发,若超时未刷新则执行预设操作。在Java中,看门狗可以用于监听状态变化、数据一致性保证、业务超时处理等场景。例如,通过设置刷新周期,可以避免短时间内大量状态更新频繁写入数据库,确保数据一致性。看门狗还可用于分布式锁的续约,防止死锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看门狗是什么

看门狗,又叫 watchdog,从本质上来说就是一个定时器电路,一般有一个输入和一个输出,其中输入叫做喂狗,输出一般连接到另外一个部分的复位端,一般是连接到单片机。

看门狗原本是一种定时器电路,但是可以借鉴它的运行模式,用来实现java程序开发的一些业务逻辑。

看门狗原理

看门狗的原理是,有一个定时器在循环计时,当有外界条件触发它执行后,刷新(重置)计时,一直等到计时完毕,还没有外界条件来触发,则会输出特定的指令或者回调。

那么看门狗如何在java中应用呢?我举个场景:当有一个对象的状态变更很频繁,你需要保证数据一致性,将对象的最终状态更新到数据库中。当短时间内有大量的状态变更时,你如何解决更新数据库过于频繁的问题?

上面列举的那个业务场景,我们就可以使用java看门狗来实现。每次状态更新看作是刷新看门狗计时,状态更新结束,看门狗计时结束,触发更新数据库。

java实现看门狗

我们还是用上面那个案例,短时间内大量且频繁的更新状态,要保证数据一致性,用看门狗来实现:

/** 看门狗,用于监听状态变化 */
public class StatusWatchDog {
    /** 刷新周期(秒) */
    private static final long SLEEP = 2;
    /** key为对象id,对象状态更新时会更新对应的value值为true */
    private static final Map<String, Boolean> MAP = new ConcurrentHashMap<>();

    /** 刷新看门狗 */
    public static void refresh(String id, Consumer<String> callback) {
        if (MAP.isEmpty()) {
            MAP.put(id, true);
            watch(callback);
        } else {
            MAP.put(id, true);
        }
    }

    /** 监视对应的状态是否进行刷新,若固定周期内未刷新,则踢出map并进行回调 */
    private static void watch(Consumer<String> callback) {
        Runnable runnable =
                () -> {
                    while (!MAP.isEmpty()) {
                        MAP.keySet()
                                .forEach(
                                        id -> {
                                            if (MAP.get(id)) {
                                                MAP.put(id, false);
                                            }
                                        });
                        try {
                            TimeUnit.SECONDS.sleep(SLEEP);
                        } catch (InterruptedException e) {
                            LogAspect.error(e.getMessage());
                        }
                        MAP.keySet()
                                .forEach(
                                        id -> {
                                            if (!MAP.get(id)) {
                                                MAP.remove(id);
                                                callback.accept(id);
                                            }
                                        });
                    }
                };
        new Thread(runnable).start();
    }
}

使用时,我们只需要调用refresh方法,传入对象的id和回调函数即可,回调函数为更新当前状态到数据的方法。看门狗的刷新周期可以修改,根据你的业务需求调整,上述代码中写的是2秒,如果超过2秒还没有状态更新,那么就会将当前的状态更新到数据库中。如果后续还有状态更新,则会继续重复此过程。

看门狗的使用场景

上面我们列举了一种使用场景,那么看门狗在java应用中还有哪些使用场景呢?

  • 可以用作监听业务,当规定时间内没有收到触发消息则做出对应动作
  • 可以用作短时间内更新大量数据的缓冲,如上述案例,频繁短暂的更新某个字段
  • 可以用作redis分布式锁的续约,获取锁之后如果超时了,需要续约才能使用,避免死锁

以上简单的列举了几种使用场景,看门狗原理在java中应用广泛,我们了解它的原理之后,就可以根据自身业务场景去使用。

<think>好的,用户现在问的是Redisson分布式实现原理。之前他们问过Redis 6.0多线程是否影响原子性,现在可能是在进一步探索如何用Redis实现分布式,尤其是在分布式系统中保证一致性和原子性。 首先,我需要回忆Redisson的分布式机制。记得Redisson主要利用Redis的Lua脚本和发布订阅功能,还有看门狗机制。用户可能想知道具体步骤,比如加、解、续期等过程,以及如何解决常见的分布式问题,比如死续期、可重入性。 用户可能关心的是Redisson如何确保在分布式环境中的的正确性,比如在加时如何防止其他客户端获取,如何避免被长时间占用,以及网络分区时的处理。此外,他们可能想了解Redisson相比其他实现(如简单的SETNX)的优势在哪里,比如自动续期、可重入等特性。 需要分步骤解释加过程,比如使用Lua脚本设置hash结构,记录客户端ID和线程ID,保证可重入性。然后看门狗机制如何定期续期,防止业务未完成过期。解时如何验证身份,避免误删其他客户端的。还要提到Redlock算法,虽然这里用户可能更关注单节点实现,但可以简单提及多节点的情况。 另外,可能需要注意用户的背景,他们可能是开发人员,需要在实际项目中使用分布式,因此需要强调Redisson如何处理常见问题,比如客户端崩溃后的释放,或者的公平性等。同时,要对比之前的问题,说明Redis的多线程不影响Redisson的原子性,因为关键操作还是由Lua脚本在单线程中执行。 最后,总结实现原理时,要突出Redisson如何利用Redis的特性,结合Lua脚本、键过期、发布订阅等机制,来构建一个健壮的分布式,同时提到可能的风险点,比如时钟跳跃问题,或者主从切换时的潜在问题,以及Redisson的解决方案。</think>以下是 Redisson 分布式实现原理详解,通过关键机制分步解析其设计思路: --- ### **一、核心数据结构** Redisson 的分布式本质是**基于 Redis 的 Hash 结构**实现,每个对应一个 Redis Key,结构如下: ```lua KEYS[1] = "my_lock" -- 的名称 ARGV[1] = 30000 -- 的过期时间(毫秒) ARGV[2] = "client1:thread1" -- 客户端唯一标识(UUID + 线程ID) ``` - **Hash 字段**:记录持有的客户端标识和重入次数 - **Key 过期时间**:防止被永久占用(宕机时自动释放) --- ### **二、加流程** #### **1. 尝试加** 使用 Lua 脚本原子化执行以下操作: ```lua if (redis.call('exists', KEYS[1]) == 0) then redis.call('hincrby', KEYS[1], ARGV[2], 1) -- 首次加,重入次数=1 redis.call('pexpire', KEYS[1], ARGV[1]) -- 设置过期时间 return nil end if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('hincrby', KEYS[1], ARGV[2], 1) -- 重入次数+1(可重入) redis.call('pexpire', KEYS[1], ARGV[1]) -- 刷新过期时间 return nil end return redis.call('pttl', KEYS[1]) -- 已被其他客户端持有,返回剩余存活时间 ``` **原子性保证**:通过 Lua 脚本确保判断状态、设置、设置过期时间的操作不可分割。 #### **2. 竞争处理** - **自旋重试**:若加失败,客户端进入循环,通过 Redis 的发布订阅(Pub/Sub)监听释放事件,收到通知后再次尝试加。 - **等待超时**:避免无限等待,设置最大等待时间。 --- ### **三、续期(Watchdog 机制)** #### **1. 后台守护线程** - **自动续期**:默认每隔 `过期时间/3`(如 10秒过期则每3.3秒续期一次)重置的过期时间。 - **防宕机泄漏**:若客户端崩溃,续期线程终止,最终自动过期释放。 #### **2. 续期逻辑** ```java if (持有 && 未释放) { redis.call('pexpire', KEYS[1], ARGV[1]); -- 刷新过期时间 } ``` --- ### **四、释放流程** ```lua if (redis.call('hexists', KEYS[1], ARGV[2]) == 0) then return nil -- 不属于当前客户端,拒绝释放 end local counter = redis.call('hincrby', KEYS[1], ARGV[2], -1) -- 重入次数-1 if (counter > 0) then redis.call('pexpire', KEYS[1], ARGV[1]) -- 仍有重入,刷新过期时间 return 0 else redis.call('del', KEYS[1]) -- 彻底释放 redis.call('publish', KEYS[2], ARGV[3]) -- 发布释放消息 return 1 end ``` **安全性**:释放时验证客户端标识,避免误删他人持有的。 --- ### **五、容错与高可用** #### **1. 多节点部署(RedLock 算法)** - **跨节点加**:向多个 Redis 节点发送加请求,当多数节点(N/2+1)加成功时,视为全局生效。 - **时钟同步问题**:依赖各节点时钟误差小于过期时间,否则可能引发冲突。 #### **2. 主从切换风险** - **异步复制**:主节点写入后宕机,若从节点未同步数据,可能导致丢失。 - **解决方案**:Redisson 提供 `RedissonRedLock` 对多主节点加,降低单点故障风险。 --- ### **六、特性总结** | **特性** | **实现方式** | |----------------|-----------------------------------------------------------------------------| | 互斥性 | Lua 脚本保证原子性,Hash 结构记录唯一持有者 | | 可重入 | Hash 值记录重入次数,同一客户端/线程可多次加 | | 自动续期 | Watchdog 后台线程定期刷新过期时间 | | 释放通知 | 通过 Redis Pub/Sub 广播释放事件,减少无效轮询 | | 宕机容错 | 设置过期时间,客户端崩溃后自动释放 | --- ### **七、适用场景与限制** - **适用场景**:分布式任务调度、资源争抢控制、幂等性保障等。 - **局限性**: - **网络分区风险**:Redis 集群脑裂时可能产生双写冲突。 - **性能开销**:Watchdog 机制和 Pub/Sub 会带来额外资源消耗。 - **时钟依赖**:依赖 Redis 服务器时钟稳定性,极端情况下可能影响有效性。 --- 通过上述机制,Redisson 实现了高性能、高可靠的分布式,是分布式系统中协调共享资源访问的核心工具之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值