redisson看门狗锁及RedissonLockUtil

文章详细描述了如何使用Redisson库在Java中实现分布式锁功能,包括获取、尝试获取、解锁等操作,以及不同方法的参数含义和应用场景。

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

public void updateHordeAdvertClickNum(HordeAdvertInfoRequest request) {
        String lockKey = "HORDE_ADVERT_CLICK_KEY:" + request.getAdvertId();
        RLock rLock = redisson.getLock(lockKey);
        try {
            boolean lock = rLock.tryLock(2L, TimeUnit.SECONDS);
            if (lock) {
                HordeAdvertInfoEntity entity = hordeAdvertInfoMapper.findById(request.getAdvertId());
                MongoUpdateWrapper wrapper = new MongoUpdateWrapper();
                Integer clickNum = entity.getClickNum()==null?0:entity.getClickNum();
                wrapper.set(HordeAdvertInfoEntity::getClickNum, clickNum+1);
                wrapper.and(HordeAdvertInfoEntity::getId).eq(request.getAdvertId());
                hordeAdvertInfoMapper.update(wrapper);
            } else {
                throw BusinessException.newParamsException("获取锁失败!");
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            rLock.unlock();
        }
    }



​
public void test() throws Exception{
        RLock lock = redissonClient.getLock("guodong");    // 拿锁失败时会不停的重试
        
        // 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30s
        lock.lock();
         
        // 具有Watch Dog 自动延期机制 默认续30s
        // 尝试拿锁10s后停止重试,返回false 具有Watch Dog 自动延期机制 默认续30s
        boolean res1 = lock.tryLock(10, TimeUnit.SECONDS); 
       
       // 没有Watch Dog 
       // 尝试获取锁10秒,如果获取不到则放弃
        lock.lock(10, TimeUnit.SECONDS);
       
       // 没有Watch Dog 
       // 尝试获取锁,等待100秒,持有锁10秒钟
        boolean res2 = lock.tryLock(100, 10, TimeUnit.SECONDS);
        
        
        Thread.sleep(40000L);
       
        
        lock.unlock();
    }

​
package com.flhy.redis.utils;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @author zengqingyu
 * @Desc: 分布式锁工具类
 */
@Component
@Slf4j
public class RedissonLockUtil {

    @Resource
    private RedissonClient client;


    private final static String SPLIT = "/";

    /**
     * 超时时间15秒(占有锁的最长时间)
     */
    private final static Integer TIMEOUT = 15;


    /**
     * 获取业务锁
     *
     * @param prefix     业务号锁前缀
     * @param businessNo 业务号
     */
    public void lock(String prefix, String businessNo) {
        RLock rLock = client.getLock(prefix + SPLIT + businessNo);
        rLock.lock(TIMEOUT, TimeUnit.SECONDS);
    }

    /**
     * 解锁
     *
     * @param prefix     业务号锁前缀
     * @param businessNo 业务号
     */
    public void unlock(String prefix, String businessNo) {
        RLock rLock = client.getLock(prefix + SPLIT + businessNo);
        try {
            if (rLock.isHeldByCurrentThread()) {
                rLock.unlock();
            }
        } catch (IllegalMonitorStateException e) {
            log.error("RedissonLockUtil lock timeout unlock", e);
        }
    }


    /**
     * 尝试获取分布式锁,带有尝试获取锁的等待时间 和 占有锁之后的释放时间
     *
     * @param prefix     业务号前缀
     * @param businessNo 业务号
     * @param waitTime   这个参数决定了在尝试获取锁时的最长等待时间。当你的程序尝试获取锁时,如果锁已经被其他进程或线程持有,它会等待一段时间,直到锁变为可用状态。
     *                   waitTime就是这个等待时间的上限。如果在这段时间内锁没有被释放,则获取锁的尝试会失败。这个参数有助于防止在锁资源上的长时间阻塞。
     * @param leaseTime  这个参数表示一旦获取了锁之后,锁将会被保持多长时间。在leaseTime期满后,锁会自动被释放。
     *                   这是一种安全措施,以防止某个进程或线程在持有锁之后忘记释放它,或因为崩溃而无法释放,从而导致其他线程或进程永远无法获取这个锁。
     *                   设置合理的leaseTime可以确保即使出现这样的情况,锁最终也会被释放,从而使得其他进程能够获取锁。
     * @return 是否抢锁成功,true:抢锁成功,false: 抢锁失败
     */
    public boolean tryLockWithWaitTimeAndLeaseTime(String prefix, String businessNo, int waitTime, int leaseTime) {
        RLock lock = client.getLock(prefix + SPLIT + businessNo);
        try {
            return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            return false;
        }
    }


    /**
     * 尝试获取分布式锁,带有尝试获取锁的等待时间
     *
     * @param prefix     业务号前缀
     * @param businessNo 业务号
     * @param waitTime   使用场景:例如,抽奖,在1秒内若该用户没有抢锁成功,则给用户返回系统繁忙,请稍后再试的文案, 单位:秒
     *                   这个参数决定了在尝试获取锁时的最长等待时间。当你的程序尝试获取锁时,如果锁已经被其他进程或线程持有,它会等待一段时间,直到锁变为可用状态。
     *                   waitTime就是这个等待时间的上限。如果在这段时间内锁没有被释放,则获取锁的尝试会失败。这个参数有助于防止在锁资源上的长时间阻塞。
     * @return 是否抢锁成功, true: 抢锁成功, false: 抢锁失败
     */
    public boolean tryLockWithWaitTime(String prefix, String businessNo, int waitTime) {
        RLock lock = client.getLock(prefix + SPLIT + businessNo);
        try {
            return lock.tryLock(waitTime, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            return false;
        }
    }

    /**
     * 尝试获取分布式锁 抢锁失败后,不会等待,立即返回成功或失败
     *
     * @param prefix     业务号前缀
     * @param businessNo 业务号,
     * @return 使用场景:例如,抽奖,若该用户没有抢锁成功,则立即给返回用户系统繁忙,请稍后再试的文案
     * 是否抢锁成功, true: 抢锁成功, false: 抢锁失败
     */
    public boolean tryLock(String prefix, String businessNo) {
        RLock lock = client.getLock(prefix + SPLIT + businessNo);
        return lock.tryLock();
    }

}

### Redisson 看门狗机制及其工作原理 Redisson看门狗机制是一种用于分布式自动续约的功能,其核心目的是解决过期导致的资源竞争问题。当一个客户端成功获取到分布式后,Redisson 会启动一个定时任务(即看门狗),定期延长的有效时间[^1]。 #### 工作原理 1. **超时设置** 当客户端请求时,可以通过参数指定的最大持有时间(TTL)。如果未显式设定,则默认采用配置中的 TTL 值[^3]。 2. **自动续期逻辑** 在被占用期间,Redisson 启动了一个后台线程——看门狗,它会在距离到期前的一段时间内触发一次续期操作。具体来说,看门狗会在剩余有效期小于一定阈值(通常是三分之一的 TTL 时间)时执行 `expire` 操作,从而延长的生命周期[^4]。 3. **多线程安全与可靠性保障** 续约过程由单个线程完成,避免因并发更新造成不必要的开销。同时,在解阶段,只有原始加者才能删除对应的键值对,这通过全局唯一 ID 来验证身份,有效防止误删其他客户端持有的。 4. **异常处理** 如果某个节点发生崩溃或其他不可控情况而未能及时释放所持之,那么经过预设时限之后该会被自动清除掉,允许其他等待中的进程重新尝试获得控制权。 #### 使用场景 - 高并发环境下的服务间协作; - 数据一致性维护,比如缓存刷新、批量数据导入导出等操作; - 资源独占访问控制,例如文件写入权限管理、数据库连接池分配等等[^2]。 #### 分布式续约注意事项 为了确保分布式系统的稳定运行以及业务连续性不受影响,在设计实现此类功能时需特别注意以下几点事项: - 设置合理的初始租约期限(TTL),既不过短以至于频繁触发续约动作增加网络负担,也不宜太长以免掩盖潜在故障隐患; - 对于长时间运行的任务考虑分段定策略减少整体风险暴露窗口; - 结合实际需求调整续约频率与提前量参数优化性能表现。 ```java RLock lock = redissonClient.getLock("anyLock"); try { boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS); // 尝试获取,最多等待10秒,上以后30秒自动解 } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); // 解 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值