redisson基础

发布于:2025-05-17 ⋅ 阅读:(255) ⋅ 点赞:(0)

介绍

官方定义:Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。

简单来讲Redisson是一个在Redis的基础上实现的分布式工具的集合。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。

Redisson实现分布式锁

  • 引入redisson依赖
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.45.1</version>
        </dependency>

温馨提示:此外还有一种引入方式,直接引入redission的starter依赖,然后在yam|文件中配置Redisson,但是不推荐这种方式,因为他会替换掉Spring官方提供的这套对 Redisson 的配置。所以我们采用@Bean手动配置。

  • RedissonConfig:配置Redisson客户端
/**
 * Redisson配置类
 */
@Configuration
public class RedissonConfig {
    @Bean
    public RedissonClient redissonClient() {
        // 配置类
        Config config = new Config();
        // 添加redis地址,这里添加了单点的地址,也可以使用config.useClusterServers()添加集群地址
        config.useSingleServer().setAddress("redis://192.168.8.100:6379").setPassword("123321");
        // 创建RedissonClient客户端对象
        return Redisson.create(config);
    }
}

以下是 Redisson 中 lock() 和 tryLock() 方法所有重载形式的详细解析,重点说明其是否支持看门狗机制,并对比不同方法的适用场景。


一、lock() 方法详解

1. 无参形式:void lock()

  • 行为:无限阻塞直到获取锁,线程会一直等待,直到锁可用或线程被中断。
  • 看门狗机制:✅ 支持
    默认启用看门狗,锁的初始租期为 30 秒,每隔 10 秒(租期的 1/3)自动续期一次,确保业务未完成时锁不会过期。
  • 适用场景:
    • 需要严格保证互斥性的场景(如金融交易、库存扣减)。
    • 无法预估业务耗时,需依赖自动续期避免锁过期。
    public void criticalTask() {
        RLock lock = redisson.getLock("criticalLock");
        lock.lock();
        try {
            // 执行耗时不确定的核心业务
            processUnpredictableTask();
        } finally {
    		if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    

2. 带租期参数:void lock(long leaseTime, TimeUnit unit)

  • 行为:获取锁后,锁在 leaseTime 时间后自动释放,无论业务是否完成。

  • 看门狗机制:❌ 不支持
    显式指定 leaseTime 会禁用看门狗,锁到期后强制释放,可能导致业务未完成时锁失效。

  • 适用场景:

    • 明确知道业务最大耗时,且能保证在 leaseTime 内完成。
    • 需要避免看门狗线程资源开销的场景。
    public void timeBoundedTask() {
        RLock lock = redisson.getLock("timedLock");
        lock.lock(60, TimeUnit.SECONDS); // 60秒后自动释放
        try {
            // 必须在60秒内完成的任务
            processTimeSensitiveTask();
        } finally {
    		if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    

二、tryLock() 方法详解

1. 无参形式:boolean tryLock()

  • 行为:立即尝试获取锁,成功返回 true,失败返回 false,不阻塞线程。

  • 看门狗机制:✅ 支持
    默认启用看门狗,锁租期为 30 秒,自动续期。

  • 适用场景:

    • 非阻塞快速失败场景,如高并发下的缓存重建。
    • 需要快速响应,避免线程阻塞。
    public void cacheRebuild(String key) {
        RLock lock = redisson.getLock("cacheLock:" + key);
        if (lock.tryLock()) {
            try {
                // 重建缓存(耗时可控)
                rebuildCache(key);
            } finally {
                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        } else {
            // 其他线程已处理,直接返回
            log.info("缓存正在重建中...");
        }
    }
    

2. 限时等待:boolean tryLock(long waitTime, TimeUnit unit)

  • 行为:在 waitTime 时间内尝试获取锁,超时返回 false,支持线程中断。
  • 看门狗机制:✅ 支持
    锁租期默认 30 秒,自动续期。
  • 适用场景:
    • 允许短暂等待的并发控制,如订单处理。
    • 平衡系统吞吐量与资源争用。
     public void processOrder(String orderId) {
            RLock lock = redisson.getLock("orderLock:" + orderId);
            try {
                if (lock.tryLock(5, TimeUnit.SECONDS)) { // 最多等待5秒
                    try {
                        // 处理订单
                        handleOrder(orderId);
                    } finally {
                        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                            lock.unlock();
                        }
                    }
                } else {
                    throw new BusiException("系统繁忙,请重试");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new BusiException("操作被中断");
            }
        }
    

3. 双重时间控制:boolean tryLock(long waitTime, long leaseTime, TimeUnit unit)

  • 行为:在 waitTime 时间内尝试获取锁,成功后锁持有 leaseTime 时间。
  • 看门狗机制:❌ 不支持
    显式指定 leaseTime 会禁用看门狗。
  • 适用场景:
    • 精确控制锁生命周期,如定时任务。
    • 已知业务耗时的场景,避免自动续期开销。
     public void scheduledJob() {
            RLock lock = redisson.getLock("scheduledJobLock");
            try {
                // 等待10秒获取锁,持有锁30秒
                if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                    try {
                        // 执行30秒内必须完成的定时任务
                        executeScheduledTask();
                    } finally {
                        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                            lock.unlock();
                        }
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    

三、方法对比与选型指南

1. 看门狗机制支持对比

方法签名 看门狗支持 阻塞行为 锁持有时间控制
void lock() ✅ 无限阻塞 自动续期
void lock(long leaseTime, TimeUnit unit) ❌ 无限阻塞 固定时间
boolean tryLock() ✅ 非阻塞 自动续期
boolean tryLock(long waitTime, ...) ✅ 限时阻塞 自动续期
boolean tryLock(long waitTime, leaseTime, ...) ❌ 限时阻塞 固定时间

2. 适用场景对比

场景特性 推荐方法 理由
严格互斥,耗时不确定 lock() 依赖看门狗自动续期,避免锁过期导致数据不一致。
已知耗时,需固定锁时间 lock(leaseTime, unit) 显式控制锁生命周期,避免看门狗线程开销。
非阻塞快速失败 tryLock() 立即返回结果,适用于高并发下的缓存击穿防护。
允许短暂等待,自动续期 tryLock(waitTime, unit) 平衡等待时间和自动续期,适合订单处理等常见业务。
精确时间控制,禁用看门狗 tryLock(waitTime, leaseTime, ...) 适用于定时任务或批处理,需确保锁在固定时间释放。

四、最佳实践与风险规避

1. 看门狗机制的风险控制

  • 风险:若业务逻辑卡死(如死循环),看门狗会无限续期,导致锁无法释放。

  • 规避:

    // 设置合理的看门狗超时时间(默认30秒)
    Config config = new Config();
    config.setLockWatchdogTimeout(60_000); // 调整为60秒
    RedissonClient redisson = Redisson.create(config);
    

2. 固定租期(leaseTime)的陷阱

  • 风险:若业务耗时超过 leaseTime,其他线程可能提前获取锁,导致数据冲突。
  • 规避:
    // 确保 leaseTime > 业务最大耗时 + 缓冲时间(如20%)
    long maxBusinessTime = 5000; // 业务最大耗时5秒
    lock.tryLock(0, maxBusinessTime * 1200, TimeUnit.MILLISECONDS); // 设置6秒
    

3. 高并发场景优化

  • 问题:大量线程同时争抢锁可能导致 Redis 压力激增。
  • 优化:结合随机退避和本地锁:
    // 使用本地锁减少Redis请求
    private final ConcurrentHashMap<String, Object> localLocks = new ConcurrentHashMap<>();
    
    public void highConcurrencyTask(String key) {
        Object localLock = localLocks.computeIfAbsent(key, k -> new Object());
        synchronized (localLock) {
            RLock redisLock = redisson.getLock(key);
            if (redisLock.tryLock(50, TimeUnit.MILLISECONDS)) {
                try {
                    // 处理业务
                } finally {
                    redisLock.unlock();
                }
            }
        }
    }
    

通过合理选择锁方法,结合业务场景和看门狗机制的特性,可以在保证数据一致性的同时,最大化系统性能和可靠性。


微信公众号

今日签到

点亮在社区的每一天
去签到