深入理解分布式锁:基于Redisson的多样化锁实现

一、引言

在现代分布式系统中,如何保证数据一致性和避免并发冲突是一个重要课题。分布式锁作为解决这一问题的关键技术,在微服务架构中发挥着重要作用。本文将基于实际项目中的枚举实现,深入探讨各种分布式锁的特点和应用场景。

二、分布式锁概述

分布式锁是一种协调机制,用于在分布式系统中的多个节点间协调对共享资源的访问。相比传统的单机锁,分布式锁需要考虑网络延迟、分区容错等因素,实现起来更加复杂。

三、 项目中的分布式锁实现

在我们分析的项目中,通过枚举实现了六种不同的分布式锁类型,每种锁都有其特定的应用场景。

1. 非公平锁 (UNFAIR_LOCK)

java 复制代码
UNFAIR_LOCK {
    @Override
    public boolean lock(LockEntity lock) {
        RLock rLock = RedisUtils.getClient().getLock(lock.getKey());
        try {
            return rLock.tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
        } catch (Exception e) {
            return false;
        }
    }
    
    @Override
    public void unlock(LockEntity lock) {
        RLock rLock = RedisUtils.getClient().getLock(lock.getKey());
        if (rLock.isHeldByCurrentThread()) {
            rLock.unlockAsync();
        }
    }
}

特点:

  • 允许线程在尝试获取锁时直接竞争
  • 可能导致某些线程长时间等待
  • 适用于对锁获取顺序没有严格要求的场景

优势: 性能较好,吞吐量高

2. 公平锁 (FAIR_LOCK)

java 复制代码
FAIR_LOCK {
    @Override
    public boolean lock(LockEntity lock) {
        RLock rLock = RedisUtils.getClient().getFairLock(lock.getKey());
        try {
            return rLock.tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
        } catch (Exception e) {
            return false;
        }
    }
    
    @Override
    public void unlock(LockEntity lock) {
        RLock rLock = RedisUtils.getClient().getFairLock(lock.getKey());
        if (rLock.isHeldByCurrentThread()) {
            rLock.unlockAsync();
        }
    }
}

特点:

  • 按照请求顺序分配锁,先请求的线程优先获得锁
  • 保证了锁获取的公平性
  • 可能影响系统吞吐量

适用场景: 对锁获取顺序有严格要求的业务场景

3. 多锁 (MULTI_LOCK)

java 复制代码
MULTI_LOCK {
    @Override
    public boolean lock(LockEntity lock) {
        RLock[] locks = lock.getKeyList().stream()
                .map(key -> RedisUtils.getClient().getLock(key))
                .toArray(RLock[]::new);
        
        RedissonMultiLock multiLock = new RedissonMultiLock(locks);
        try {
            return multiLock.tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
        } catch (Exception e) {
            return false;
        }
    }
    
    @Override
    public void unlock(LockEntity lock) {
        RLock[] locks = lock.getKeyList().stream()
                .map(key -> RedisUtils.getClient().getLock(key))
                .toArray(RLock[]::new);
        RedissonMultiLock multiLock = new RedissonMultiLock(locks);
        multiLock.unlock();
    }
}

特点:

  • 将多个锁绑定为一个锁
  • 只有当所有锁都获取成功时才算获取成功
  • 适用于需要同时获取多个资源锁的场景

4. 红锁 (RED_LOCK)

java 复制代码
RED_LOCK {
    @Override
    public boolean lock(LockEntity lock) {
        RLock[] locks = lock.getKeyList().stream()
                .map(key -> RedisUtils.getClient().getLock(key))
                .toArray(RLock[]::new);
        
        RedissonRedLock redLock = new RedissonRedLock(locks);
        try {
            return redLock.tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
        } catch (Exception e) {
            return false;
        }
    }
    
    @Override
    public void unlock(LockEntity lock) {
        RLock[] locks = lock.getKeyList().stream()
                .map(key -> RedisUtils.getClient().getLock(key))
                .toArray(RLock[]::new);
        RedissonRedLock redLock = new RedissonRedLock(locks);
        redLock.unlock();
    }
}

特点:

  • 基于RedLock算法实现
  • 通过多个独立的Redis节点保证高可用性
  • 即使部分Redis节点故障,仍能保证锁的正确性

适用场景: 对高可用性要求极高的分布式环境

5. 读锁 (READ_LOCK)

java 复制代码
READ_LOCK {
    @Override
    public boolean lock(LockEntity lock) {
        RReadWriteLock rLock = RedisUtils.getClient().getReadWriteLock(lock.getKey());
        try {
            return rLock.readLock().tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
        } catch (Exception e) {
            return false;
        }
    }
    
    @Override
    public void unlock(LockEntity lock) {
        RReadWriteLock rLock = RedisUtils.getClient().getReadWriteLock(lock.getKey());
        if (rLock.readLock().isHeldByCurrentThread()) {
            rLock.readLock().unlockAsync();
        }
    }
}

6. 写锁 (WRITE_LOCK)

java 复制代码
WRITE_LOCK {
    @Override
    public boolean lock(LockEntity lock) {
        RReadWriteLock rLock = RedisUtils.getClient().getReadWriteLock(lock.getKey());
        try {
            return rLock.writeLock().tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
        } catch (Exception e) {
            return false;
        }
    }
    
    @Override
    public void unlock(LockEntity lock) {
        RReadWriteLock rLock = RedisUtils.getClient().getReadWriteLock(lock.getKey());
        if (rLock.writeLock().isHeldByCurrentThread()) {
            rLock.writeLock().unlockAsync();
        }
    }
}

读写锁特点:

  • 读锁: 允许多个线程同时读取共享资源,适用于读多写少的场景
  • 写锁: 独占访问共享资源,确保写入操作的原子性和一致性

四、实际应用案例

在项目中的类中,我们可以看到写锁的实际应用,现附上代码可直接使用:

pom.xml

xml 复制代码
    <dependency>
      <groupId>org.redisson</groupId>
      <artifactId>redisson-spring-data-27</artifactId>
      <version>3.52.0</version>
    </dependency>

LockEntity.java

java 复制代码
import lombok.Getter;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁实体类,用于封装分布式锁的相关配置参数
 */
@Getter
public class LockEntity {
    // 锁的键值
    private String key;
    // 获取锁的等待时间,默认60秒
    private long waitTime = 60L;
    // 锁的租约时间,默认-1表示永不过期
    private long leaseTime = -1L;
    // 时间单位,默认为秒
    private TimeUnit timeUnit;
    // 锁键值列表,用于批量操作
    private List<String> keyList;

    /**
     * 构造函数,初始化锁实体
     * @param key 锁的键值
     */
    public LockEntity(String key) {
        this.timeUnit = TimeUnit.SECONDS;
        this.key = key;
    }

    /**
     * 解析分布式锁注解,将注解中的配置设置到当前对象
     * @param anno 分布式锁注解
     * @return 返回当前对象实例,支持链式调用
     */
    public LockEntity parseLockAnno(DistributeLock anno) {
        return this.setKey(anno.key())
                .setWaitTime(anno.waitTime())
                .setLeaseTime(anno.leaseTime())
                .setTimeUnit(anno.timeUnit());
    }

    public LockEntity setKey(final String key) {
        this.key = key;
        return this;
    }

    public LockEntity setWaitTime(final long waitTime) {
        this.waitTime = waitTime;
        return this;
    }

    public LockEntity setLeaseTime(final long leaseTime) {
        this.leaseTime = leaseTime;
        return this;
    }

    public LockEntity setTimeUnit(final TimeUnit timeUnit) {
        this.timeUnit = timeUnit;
        return this;
    }

    public LockEntity setKeyList(final List<String> keyList) {
        this.keyList = keyList;
        return this;
    }

    @Override
    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof LockEntity)) {
            return false;
        } else {
            LockEntity other = (LockEntity)o;
            if (!other.canEqual(this)) {
                return false;
            } else if (this.getWaitTime() != other.getWaitTime()) {
                return false;
            } else if (this.getLeaseTime() != other.getLeaseTime()) {
                return false;
            } else {
                label52: {
                    Object this$key = this.getKey();
                    Object other$key = other.getKey();
                    if (this$key == null) {
                        if (other$key == null) {
                            break label52;
                        }
                    } else if (this$key.equals(other$key)) {
                        break label52;
                    }
                    return false;
                }

                Object this$timeUnit = this.getTimeUnit();
                Object other$timeUnit = other.getTimeUnit();
                if (this$timeUnit == null) {
                    if (other$timeUnit != null) {
                        return false;
                    }
                } else if (!this$timeUnit.equals(other$timeUnit)) {
                    return false;
                }

                Object this$keyList = this.getKeyList();
                Object other$keyList = other.getKeyList();
                if (this$keyList == null) {
                    if (other$keyList != null) {
                        return false;
                    }
                } else if (!this$keyList.equals(other$keyList)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(final Object other) {
        return other instanceof LockEntity;
    }

    @Override
    public int hashCode() {
        int result = 1;
        long $waitTime = this.getWaitTime();
        result = result * 59 + Long.hashCode($waitTime);
        long $leaseTime = this.getLeaseTime();
        result = result * 59 + Long.hashCode($leaseTime);
        Object $key = this.getKey();
        result = result * 59 + ($key == null ? 43 : $key.hashCode());
        Object $timeUnit = this.getTimeUnit();
        result = result * 59 + ($timeUnit == null ? 43 : $timeUnit.hashCode());
        Object $keyList = this.getKeyList();
        result = result * 59 + ($keyList == null ? 43 : $keyList.hashCode());
        return result;
    }

    @Override
    public String toString() {
        return "LockEntity(key=" + this.getKey() +
                ", waitTime=" + this.getWaitTime() +
                ", leaseTime=" + this.getLeaseTime() +
                ", timeUnit=" + this.getTimeUnit() +
                ", keyList=" + this.getKeyList() + ")";
    }

    public LockEntity() {
        this.timeUnit = TimeUnit.SECONDS;
    }
}

DistributeLock.java

java 复制代码
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁注解
 *
 * 用于在方法级别添加分布式锁功能,支持多种锁类型和键生成策略
 * 通过AOP方式实现,在方法执行前获取锁,方法执行完成后释放锁
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributeLock {
    /**
     * 锁键
     */
    String key() default "";

    /**
     * 键类型
     *
     * 指定锁键的生成策略
     * @see KeyType
     */
    KeyType keyType() default KeyType.STRING;

    /**
     * 锁类型
     *
     * 指定分布式锁的实现类型
     * @see LockType
     */
    LockType lockType() default LockType.FAIR_LOCK;

    /**
     * 等待时间
     *
     * 尝试获取锁的最大等待时间
     * 默认60秒
     */
    long waitTime() default 60L;

    /**
     * 锁的持有时间
     *
     * 锁的持有时间,-1表示永不过期
     * 默认-1(永不过期)
     */
    long leaseTime() default -1L;

    /**
     * 时间单位
     */
    TimeUnit timeUnit() default TimeUnit.SECONDS;
}

RedisUtils.java

java 复制代码
import cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import java.time.Duration;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.redisson.api.BatchResult;
import org.redisson.api.ObjectListener;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RBatch;
import org.redisson.api.RBucket;
import org.redisson.api.RBucketAsync;
import org.redisson.api.RKeys;
import org.redisson.api.RList;
import org.redisson.api.RListAsync;
import org.redisson.api.RMap;
import org.redisson.api.RMapAsync;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RSet;
import org.redisson.api.RTopic;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;

/**
 * Redis 工具类,封装了 Redisson 客户端的常用操作
 */
@Slf4j
public class RedisUtils {
    private static final RedissonClient CLIENT;

    static {
        // 初始化 Redisson 客户端,添加空值检查
        CLIENT = SpringUtil.getBean(RedissonClient.class);
        if (CLIENT == null) {
            throw new IllegalStateException("RedissonClient bean not found in Spring context");
        }
    }

    /**
     * 限流器操作
     *
     * @param key         限流器键
     * @param rateType    限流类型
     * @param rate        速率
     * @param rateInterval 速率间隔时间(秒)
     * @return 可用许可数,-1表示获取失败
     */
    public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        rateLimiter.trySetRate(rateType, (long) rate, (long) rateInterval, RateIntervalUnit.SECONDS);
        return rateLimiter.tryAcquire() ? rateLimiter.availablePermits() : -1L;
    }

    /**
     * 获取 Redisson 客户端实例
     *
     * @return Redisson 客户端实例
     */
    public static RedissonClient getClient() {
        return CLIENT;
    }

    /**
     * 发布消息到指定频道
     *
     * @param channelKey 频道键
     * @param msg        消息对象
     * @param <T>        消息类型
     */
    public static <T> void publish(String channelKey, T msg, Consumer<T> consumer) {
        if (channelKey == null || consumer == null) {
            throw new IllegalArgumentException("ChannelKey and consumer cannot be null");
        }

        RTopic topic = CLIENT.getTopic(channelKey);
        topic.publish(msg);
        consumer.accept(msg);
    }

    /**
     * 发布消息到指定频道
     *
     * @param channelKey 频道键
     * @param msg        消息对象
     * @param <T>        消息类型
     */
    public static <T> void publish(String channelKey, T msg) {
        if (channelKey == null) {
            throw new IllegalArgumentException("ChannelKey cannot be null");
        }

        RTopic topic = CLIENT.getTopic(channelKey);
        topic.publish(msg);
    }

    /**
     * 订阅指定频道的消息
     *
     * @param channelKey 频道键
     * @param clazz      消息类型
     * @param consumer   消息消费处理器
     * @param <T>        消息类型
     */
    public static <T> void subscribe(String channelKey, Class<T> clazz, Consumer<T> consumer) {
        if (channelKey == null || clazz == null || consumer == null) {
            throw new IllegalArgumentException("ChannelKey, clazz and consumer cannot be null");
        }

        RTopic topic = CLIENT.getTopic(channelKey);
        topic.addListener(clazz, (channel, msg) -> consumer.accept(msg));
    }

    /**
     * 根据模式匹配获取所有键
     *
     * @param pattern 键模式
     * @return 匹配的键集合
     */
    public static Collection<String> keys(final String pattern) {
        if (pattern == null || pattern.trim().isEmpty()) {
            throw new IllegalArgumentException("Pattern cannot be null or empty");
        }

        Stream<String> stream = CLIENT.getKeys().getKeysStreamByPattern(pattern);
        return stream.collect(Collectors.toList());
    }

    /**
     * 根据模式删除匹配的键
     *
     * @param pattern 键模式
     */
    public static void deleteKeys(final String pattern) {
        if (pattern == null || pattern.trim().isEmpty()) {
            throw new IllegalArgumentException("Pattern cannot be null or empty");
        }

        CLIENT.getKeys().deleteByPattern(pattern);
    }

    /**
     * 判断键是否存在
     *
     * @param key 键
     * @return 是否存在
     */
    public static Boolean hasKey(String key) {
        if (key == null) {
            return false;
        }
        return CLIENT.getBucket(key).isExists();
    }

    /**
     * 获取键的剩余过期时间
     *
     * @param key 键
     * @return 剩余过期时间(毫秒)
     */
    public static long getExpireTime(String key) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }
        return CLIENT.getBucket(key).remainTimeToLive();
    }

    /**
     * 设置键的过期时间
     *
     * @param key     键
     * @param timeout 过期时间(秒)
     * @return 设置是否成功
     */
    public static boolean expire(final String key, final long timeout) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }
        return expire(key, Duration.ofSeconds(timeout));
    }

    /**
     * 设置键的过期时间
     *
     * @param key      键
     * @param duration 过期时间
     * @return 设置是否成功
     */
    public static boolean expire(final String key, final Duration duration) {
        if (key == null || duration == null) {
            throw new IllegalArgumentException("Key and duration cannot be null");
        }

        RBucket<Object> rBucket = CLIENT.getBucket(key);
        return rBucket.expire(duration);
    }

    /**
     * 设置缓存对象
     *
     * @param key   键
     * @param value 值
     * @param <T>   值类型
     */
    public static <T> void setCacheObject(final String key, final T value) {
        setCacheObject(key, value, false);
    }

    /**
     * 设置缓存对象,支持保留TTL
     *
     * @param key       键
     * @param value     值
     * @param isSaveTtl 是否保留TTL
     * @param <T>       值类型
     */
    public static <T> void setCacheObject(final String key, final T value, final boolean isSaveTtl) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RBucket<T> bucket = CLIENT.getBucket(key);
        if (isSaveTtl) {
            try {
                bucket.setAndKeepTTL(value);
            } catch (Exception e) {
                log.warn("Failed to keep TTL for key '{}', falling back to regular set: {}", key, e.getMessage());
                long timeToLive = bucket.remainTimeToLive();
                setCacheObject(key, value, Duration.ofMillis(timeToLive));
            }
        } else {
            bucket.set(value);
        }
    }

    /**
     * 设置缓存对象并设置过期时间
     *
     * @param key      键
     * @param value    值
     * @param duration 过期时间
     * @param <T>      值类型
     */
    public static <T> void setCacheObject(final String key, final T value, final Duration duration) {
        if (key == null || duration == null) {
            throw new IllegalArgumentException("Key and duration cannot be null");
        }

        RBatch batch = CLIENT.createBatch();
        RBucketAsync<T> bucket = batch.getBucket(key);
        bucket.setAsync(value);
        bucket.expireAsync(duration);
        batch.execute();
    }

    /**
     * 如果键不存在则设置值
     *
     * @param key      键
     * @param value    值
     * @param duration 过期时间
     * @param <T>      值类型
     * @return 是否设置成功
     */
    public static <T> boolean setObjectIfAbsent(final String key, final T value, final Duration duration) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RBucket<T> bucket = CLIENT.getBucket(key);
        return bucket.setIfAbsent(value, duration);
    }

    /**
     * 如果键存在则设置值
     *
     * @param key      键
     * @param value    值
     * @param duration 过期时间
     * @param <T>      值类型
     * @return 是否设置成功
     */
    public static <T> boolean setObjectIfExists(final String key, final T value, final Duration duration) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RBucket<T> bucket = CLIENT.getBucket(key);
        return bucket.setIfExists(value, duration);
    }

    /**
     * 为键添加监听器
     *
     * @param key       键
     * @param listener  监听器
     * @param <T>       值类型
     */
    public static <T> void addObjectListener(final String key, final ObjectListener listener) {
        if (key == null || listener == null) {
            throw new IllegalArgumentException("Key and listener cannot be null");
        }

        RBucket<T> result = CLIENT.getBucket(key);
        result.addListener(listener);
    }

    /**
     * 获取缓存对象
     *
     * @param key 键
     * @param <T> 值类型
     * @return 缓存值
     */
    public static <T> T getCacheObject(final String key) {
        if (key == null) {
            return null;
        }

        RBucket<T> rBucket = CLIENT.getBucket(key);
        return rBucket.get();
    }

    /**
     * 删除缓存对象
     *
     * @param key 键
     * @return 是否删除成功
     */
    public static boolean deleteObject(final String key) {
        if (key == null) {
            return false;
        }
        return CLIENT.getBucket(key).delete();
    }

    /**
     * 批量删除缓存对象
     *
     * @param keys 键集合
     */
    public static void deleteObject(final Collection<String> keys) {
        if (CollUtil.isEmpty(keys)) {
            return;
        }

        RBatch batch = CLIENT.createBatch();
        for (String key : keys) {
            if (key != null) {
                batch.getBucket(key).deleteAsync();
            }
        }
        batch.execute();
    }

    /**
     * 判断缓存对象是否存在
     *
     * @param key 键
     * @return 是否存在
     */
    public static boolean isExistsObject(final String key) {
        if (key == null) {
            return false;
        }
        return CLIENT.getBucket(key).isExists();
    }

    /**
     * 覆盖缓存列表
     *
     * @param key       键
     * @param dataList  数据列表
     * @param <T>       列表元素类型
     * @return 批量执行结果
     */
    public static <T> BatchResult setCacheListOverride(final String key, final List<T> dataList) {
        return setCacheListOverride(key, dataList, null);
    }

    /**
     * 覆盖缓存列表并设置过期时间
     *
     * @param key       键
     * @param dataList  数据列表
     * @param duration  过期时间
     * @param <T>       列表元素类型
     * @return 批量执行结果
     */
    public static <T> BatchResult setCacheListOverride(final String key, final List<T> dataList, Duration duration) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RBatch batch = CLIENT.createBatch();
        batch.getBucket(key).deleteAsync();
        if (dataList != null && !dataList.isEmpty()) {
            batch.getList(key).addAllAsync(dataList);
        }

        if (duration != null) {
            batch.getList(key).expireAsync(duration);
        }
        return batch.execute();
    }

    /**
     * 设置列表指定索引位置的值
     *
     * @param key   键
     * @param index 索引
     * @param data  数据
     * @param <T>   元素类型
     * @return 旧值
     */
    public static <T> T setCacheListIndex(final String key, final int index, final T data) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RList<T> rList = CLIENT.getList(key);
        return rList.set(index, data);
    }

    /**
     * 向缓存列表添加元素
     *
     * @param key       键
     * @param dataList  数据列表
     * @param <T>       列表元素类型
     * @return 是否添加成功
     */
    public static <T> boolean addCacheList(final String key, final List<T> dataList) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RList<T> rList = CLIENT.getList(key);
        return rList.addAll(dataList);
    }

    /**
     * 向缓存列表添加元素并设置过期时间
     *
     * @param key       键
     * @param dataList  数据列表
     * @param duration  过期时间
     * @param <T>       列表元素类型
     * @return 批量执行结果
     */
    public static <T> BatchResult addCacheList(final String key, final List<T> dataList, Duration duration) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RBatch batch = CLIENT.createBatch();
        RListAsync<T> list = batch.getList(key);
        list.addAllAsync(dataList);

        if (duration != null) {
            list.expireAsync(duration);
        }
        return batch.execute();
    }

    /**
     * 向缓存列表头部添加元素
     *
     * @param key  键
     * @param data 数据
     * @param <T>  元素类型
     */
    public static <T> void addCacheListFirst(final String key, final List<T> data) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RList<T> rList = CLIENT.getList(key);
        rList.addAll(0, data);
    }

    /**
     * 向缓存列表添加元素
     *
     * @param key  键
     * @param data 数据
     * @param <T>  元素类型
     * @return 是否添加成功
     */
    public static <T> boolean addCacheList(final String key, final T data) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RList<T> rList = CLIENT.getList(key);
        return rList.add(data);
    }

    /**
     * 向缓存列表头部添加元素
     *
     * @param key  键
     * @param data 数据
     * @param <T>  元素类型
     */
    public static <T> void addCacheListFirst(final String key, final T data) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RList<T> rList = CLIENT.getList(key);
        rList.add(0, data);
    }

    /**
     * 为列表添加监听器
     *
     * @param key       键
     * @param listener  监听器
     * @param <T>       列表元素类型
     */
    public static <T> void addListListener(final String key, final ObjectListener listener) {
        if (key == null || listener == null) {
            throw new IllegalArgumentException("Key and listener cannot be null");
        }

        RList<T> rList = CLIENT.getList(key);
        rList.addListener(listener);
    }

    /**
     * 获取缓存列表
     *
     * @param key 键
     * @param <T> 列表元素类型
     * @return 列表数据
     */
    public static <T> List<T> getCacheList(final String key) {
        if (key == null) {
            return Collections.emptyList();
        }

        RList<T> rList = CLIENT.getList(key);
        return rList.readAll();
    }

    /**
     * 获取缓存列表范围数据
     *
     * @param key  键
     * @param from 起始索引
     * @param to   结束索引
     * @param <T>  列表元素类型
     * @return 列表数据
     */
    public static <T> List<T> getCacheListRange(final String key, int from, int to) {
        if (key == null) {
            return Collections.emptyList();
        }

        RList<T> rList = CLIENT.getList(key);
        return rList.range(from, to);
    }

    /**
     * 获取缓存列表指定索引位置的元素
     *
     * @param key   键
     * @param index 索引
     * @param <T>   元素类型
     * @return 元素值
     */
    public static <T> T getCacheListIndex(final String key, final int index) {
        if (key == null) {
            return null;
        }

        RList<T> rList = CLIENT.getList(key);
        return rList.get(index);
    }

    /**
     * 移除缓存列表指定索引位置的元素
     *
     * @param key   键
     * @param index 索引
     */
    public static <T> void removeCacheListIndex(final String key, final int index) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RList<T> rList = CLIENT.getList(key);
        rList.fastRemove(index);
    }

    /**
     * 移除缓存列表中指定元素
     *
     * @param key     键
     * @param element 元素
     * @param count   移除数量
     * @param <T>     元素类型
     * @return 是否移除成功
     */
    public static <T> boolean removeCacheListCount(final String key, final T element, final int count) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RList<T> rList = CLIENT.getList(key);
        return rList.remove(element, count);
    }

    /**
     * 向缓存集合添加元素
     *
     * @param key      键
     * @param dataSet  数据集
     * @param <T>      元素类型
     * @return 是否添加成功
     */
    public static <T> boolean addCacheSet(final String key, final Set<T> dataSet) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RSet<T> rSet = CLIENT.getSet(key);
        return rSet.addAll(dataSet);
    }

    /**
     * 向缓存集合添加元素
     *
     * @param key  键
     * @param data 数据
     * @param <T>  元素类型
     * @return 是否添加成功
     */
    public static <T> boolean addCacheSet(final String key, final T data) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RSet<T> rSet = CLIENT.getSet(key);
        return rSet.add(data);
    }

    /**
     * 为集合添加监听器
     *
     * @param key       键
     * @param listener  监听器
     * @param <T>       集合元素类型
     */
    public static <T> void addSetListener(final String key, final ObjectListener listener) {
        if (key == null || listener == null) {
            throw new IllegalArgumentException("Key and listener cannot be null");
        }

        RSet<T> rSet = CLIENT.getSet(key);
        rSet.addListener(listener);
    }

    /**
     * 获取缓存集合
     *
     * @param key 键
     * @param <T> 集合元素类型
     * @return 集合数据
     */
    public static <T> Set<T> getCacheSet(final String key) {
        if (key == null) {
            return Collections.emptySet();
        }

        RSet<T> rSet = CLIENT.getSet(key);
        return rSet.readAll();
    }

    /**
     * 向缓存Map添加数据
     *
     * @param key     键
     * @param dataMap 数据映射
     * @param <T>     值类型
     */
    public static <T> void addCacheMap(final String key, final Map<String, T> dataMap) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        if (!CollUtil.isEmpty(dataMap)) {
            RMap<String, T> rMap = CLIENT.getMap(key);
            rMap.putAll(dataMap);
        }
    }

    /**
     * 覆盖缓存Map
     *
     * @param key     键
     * @param dataMap 数据映射
     * @param <T>     值类型
     * @return 批量执行结果
     */
    public static <T> BatchResult setCacheMapOverride(final String key, final Map<String, T> dataMap) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        if (CollUtil.isEmpty(dataMap)) {
            return null;
        }

        RBatch batch = CLIENT.createBatch();
        RMapAsync<String, T> map = batch.getMap(key);
        map.clearAsync();
        map.putAllAsync(dataMap);
        return batch.execute();
    }

    /**
     * 为Map添加监听器
     *
     * @param key       键
     * @param listener  监听器
     * @param <T>       Map值类型
     */
    public static <T> void addMapListener(final String key, final ObjectListener listener) {
        if (key == null || listener == null) {
            throw new IllegalArgumentException("Key and listener cannot be null");
        }

        RMap<String, T> rMap = CLIENT.getMap(key);
        rMap.addListener(listener);
    }

    /**
     * 获取缓存Map
     *
     * @param key 键
     * @param <T> 值类型
     * @return Map数据
     */
    public static <T> Map<String, T> getCacheMap(final String key) {
        if (key == null) {
            return Collections.emptyMap();
        }

        RMap<String, T> rMap = CLIENT.getMap(key);
        return rMap.getAll(rMap.keySet());
    }

    /**
     * 获取缓存Map的键集合
     *
     * @param key 键
     * @param <T> 值类型
     * @return 键集合
     */
    public static <T> Set<String> getCacheMapKeySet(final String key) {
        if (key == null) {
            return Collections.emptySet();
        }

        RMap<String, T> rMap = CLIENT.getMap(key);
        return rMap.keySet();
    }

    /**
     * 设置缓存Map的值
     *
     * @param key   键
     * @param hKey  哈希键
     * @param value 值
     * @param <T>   值类型
     */
    public static <T> void setCacheMapValue(final String key, final String hKey, final T value) {
        if (key == null || hKey == null) {
            throw new IllegalArgumentException("Key and hKey cannot be null");
        }

        RMap<String, T> rMap = CLIENT.getMap(key);
        rMap.put(hKey, value);
    }

    /**
     * 获取缓存Map的值
     *
     * @param key  键
     * @param hKey 哈希键
     * @param <T>  值类型
     * @return 值
     */
    public static <T> T getCacheMapValue(final String key, final String hKey) {
        if (key == null || hKey == null) {
            return null;
        }

        RMap<String, T> rMap = CLIENT.getMap(key);
        return rMap.get(hKey);
    }

    /**
     * 删除缓存Map的值
     *
     * @param key  键
     * @param hKey 哈希键
     * @param <T>  值类型
     * @return 删除的值
     */
    public static <T> T delCacheMapValue(final String key, final String hKey) {
        if (key == null || hKey == null) {
            return null;
        }

        RMap<String, T> rMap = CLIENT.getMap(key);
        return rMap.remove(hKey);
    }

    /**
     * 批量删除缓存Map的值
     *
     * @param key  键
     * @param hKeys 哈希键集合
     * @param <T>  值类型
     */
    public static <T> void delMultiCacheMapValue(final String key, final Set<String> hKeys) {
        if (key == null || CollUtil.isEmpty(hKeys)) {
            return;
        }

        RBatch batch = CLIENT.createBatch();
        RMapAsync<String, T> rMap = batch.getMap(key);

        for (String hKey : hKeys) {
            if (hKey != null) {
                rMap.removeAsync(hKey);
            }
        }

        batch.execute();
    }

    /**
     * 批量获取缓存Map的值
     *
     * @param key  键
     * @param hKeys 哈希键集合
     * @param <K>  键类型
     * @param <V>  值类型
     * @return 值映射
     */
    public static <K, V> Map<K, V> getMultiCacheMapValue(final String key, final Set<K> hKeys) {
        if (key == null || CollUtil.isEmpty(hKeys)) {
            return Collections.emptyMap();
        }

        RMap<K, V> rMap = CLIENT.getMap(key);
        return rMap.getAll(hKeys);
    }

    /**
     * 设置原子值
     *
     * @param key   键
     * @param value 值
     */
    public static void setAtomicValue(String key, long value) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RAtomicLong atomic = CLIENT.getAtomicLong(key);
        atomic.set(value);
    }

    /**
     * 获取原子值
     *
     * @param key 键
     * @return 原子值
     */
    public static long getAtomicValue(String key) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RAtomicLong atomic = CLIENT.getAtomicLong(key);
        return atomic.get();
    }

    /**
     * 原子值自增
     *
     * @param key 键
     * @return 自增后的值
     */
    public static long incrAtomicValue(String key) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RAtomicLong atomic = CLIENT.getAtomicLong(key);
        return atomic.incrementAndGet();
    }

    /**
     * 原子值自减
     *
     * @param key 键
     * @return 自减后的值
     */
    public static long decrAtomicValue(String key) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }

        RAtomicLong atomic = CLIENT.getAtomicLong(key);
        return atomic.decrementAndGet();
    }

    private RedisUtils() {
        // 工具类私有构造函数
    }
}

SpelUtils.java

java 复制代码
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

/**
 * Spring Expression Language (SpEL) 工具类
 * 提供解析和执行 SpEL 表达式的功能,通常用于 AOP 切面中获取方法参数值
 */
public class SpelUtils {
    private static final ExpressionParser expressionParser = new SpelExpressionParser();
    private static final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();

    /**
     * 解析 SpEL 表达式并返回字符串结果
     *
     * @param joinPoint 切点连接点,包含方法执行的相关信息
     * @param value SpEL 表达式字符串
     * @return 解析后的字符串结果
     */
    public static String parse(JoinPoint joinPoint, String value) {
        EvaluationContext context = getContext(joinPoint.getArgs(), getMethod(joinPoint));
        return (String)getValue(context, value, String.class);
    }

    /**
     * 获取表达式的值
     *
     * @param context SpEL 上下文环境
     * @param value SpEL 表达式字符串
     * @param clazz 返回值类型
     * @param <T> 泛型类型
     * @return 表达式计算结果
     */
    private static <T> T getValue(EvaluationContext context, String value, Class<T> clazz) {
        Expression expression = expressionParser.parseExpression(value);
        return expression.getValue(context, clazz);
    }

    /**
     * 创建 SpEL 上下文环境,并将方法参数设置为上下文中的变量
     *
     * @param arguments 方法参数数组
     * @param signatureMethod 方法签名对象
     * @return 包含方法参数作为变量的上下文环境
     */
    private static EvaluationContext getContext(Object[] arguments, Method signatureMethod) {
        String[] parameterNames = parameterNameDiscoverer.getParameterNames(signatureMethod);
        EvaluationContext context = new StandardEvaluationContext();
        if (parameterNames == null) {
            return context;
        } else {
            for(int i = 0; i < arguments.length; ++i) {
                // 将参数名称与对应值设置到上下文中,便于 SpEL 表达式引用
                context.setVariable(parameterNames[i], arguments[i]);
            }

            return context;
        }
    }

    /**
     * 获取切点对应的方法对象
     * 处理接口代理的情况,确保获取到实际实现类的方法
     *
     * @param point 切点连接点
     * @return 方法对象
     */
    public static Method getMethod(JoinPoint point) {
        try {
            MethodSignature signature = (MethodSignature)point.getSignature();
            Method method = signature.getMethod();
            // 如果方法来自接口,则获取目标类的实际实现方法
            return !method.getDeclaringClass().isInterface() ? method : point.getTarget().getClass().getDeclaredMethod(point.getSignature().getName(), method.getParameterTypes());
        } catch (NoSuchMethodException var3) {
            NoSuchMethodException e = var3;
            throw new RuntimeException(e);
        }
    }

    private SpelUtils() {
    }
}

LockType.java

java 复制代码
import org.redisson.RedissonMultiLock;
import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;

/**
 * 分布式锁类型枚举
 * 该枚举定义了多种分布式锁实现类型,包括公平锁、非公平锁、多锁、红锁和读写锁
 * 每种锁类型都实现了统一的加锁和解锁接口,便于在不同场景下灵活选择
 *
 */
public enum LockType {

    /**
     * 非公平锁
     * 非公平锁允许线程在尝试获取锁时直接竞争,可能导致某些线程长时间等待
     * 适用于对锁获取顺序没有严格要求的场景
     */
    UNFAIR_LOCK {
        @Override
        public boolean lock(LockEntity lock) {
            RLock rLock = RedisUtils.getClient().getLock(lock.getKey());

            try {
                // 尝试获取锁,设置等待时间和持有时间
                return rLock.tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
            } catch (Exception e) {
                return false;
            }
        }

        @Override
        public void unlock(LockEntity lock) {
            RLock rLock = RedisUtils.getClient().getLock(lock.getKey());
            // 确保当前线程持有锁才执行解锁
            if (rLock.isHeldByCurrentThread()) {
                rLock.unlockAsync(); // 异步解锁,提高性能
            }
        }
    },

    /**
     * 公平锁
     *
     * 公平锁按照请求顺序分配锁,先请求的线程优先获得锁
     * 保证了锁获取的公平性,但可能影响吞吐量
     */
    FAIR_LOCK {
        @Override
        public boolean lock(LockEntity lock) {
            // 获取公平锁实例
            RLock rLock = RedisUtils.getClient().getFairLock(lock.getKey());

            try {
                // 尝试获取公平锁
                return rLock.tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
            } catch (Exception e) {
                return false;
            }
        }

        @Override
        public void unlock(LockEntity lock) {
            RLock rLock = RedisUtils.getClient().getFairLock(lock.getKey());
            if (rLock.isHeldByCurrentThread()) {
                rLock.unlockAsync();
            }
        }
    },

    /**
     * 多锁(MultiLock)
     *
     * MultiLock 将多个锁绑定为一个锁,只有当所有锁都获取成功时才算获取成功
     * 适用于需要同时获取多个资源锁的场景
     */
    MULTI_LOCK {
        @Override
        public boolean lock(LockEntity lock) {
            // 将锁键列表转换为RLock数组
            RLock[] locks = lock.getKeyList().stream()
                    .map(key -> RedisUtils.getClient().getLock(key))
                    .toArray(RLock[]::new);

            // 创建MultiLock实例
            RedissonMultiLock multiLock = new RedissonMultiLock(locks);

            try {
                // 尝试获取所有锁
                return multiLock.tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
            } catch (Exception e) {
                return false;
            }
        }

        @Override
        public void unlock(LockEntity lock) {
            RLock[] locks = lock.getKeyList().stream()
                    .map(key -> RedisUtils.getClient().getLock(key))
                    .toArray(RLock[]::new);
            RedissonMultiLock multiLock = new RedissonMultiLock(locks);
            // 释放所有锁
            multiLock.unlock();
        }
    },

    /**
     * 红锁(RedLock)
     *
     * RedLock 是一种高可用的分布式锁算法,通过多个独立的Redis节点实现
     * 即使部分Redis节点故障,仍能保证锁的正确性
     */
    RED_LOCK {
        @Override
        public boolean lock(LockEntity lock) {
            // 获取多个锁实例,用于实现RedLock算法
            RLock[] locks = lock.getKeyList().stream()
                    .map(key -> RedisUtils.getClient().getLock(key))
                    .toArray(RLock[]::new);

            // 创建RedLock实例
            RedissonRedLock redLock = new RedissonRedLock(locks);

            try {
                // 尝试获取红锁
                return redLock.tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
            } catch (Exception e) {
                return false;
            }
        }

        @Override
        public void unlock(LockEntity lock) {
            RLock[] locks = lock.getKeyList().stream()
                    .map(key -> RedisUtils.getClient().getLock(key))
                    .toArray(RLock[]::new);
            RedissonRedLock redLock = new RedissonRedLock(locks);
            // 释放红锁
            redLock.unlock();
        }
    },

    /**
     * 读锁
     *
     * 读写锁中的读锁,允许多个线程同时读取共享资源
     * 适用于读多写少的场景,提高并发性能
     */
    READ_LOCK {
        @Override
        public boolean lock(LockEntity lock) {
            // 获取读写锁实例的读锁部分
            RReadWriteLock rLock = RedisUtils.getClient().getReadWriteLock(lock.getKey());

            try {
                // 尝试获取读锁
                return rLock.readLock().tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
            } catch (Exception e) {
                return false;
            }
        }

        @Override
        public void unlock(LockEntity lock) {
            RReadWriteLock rLock = RedisUtils.getClient().getReadWriteLock(lock.getKey());
            // 检查当前线程是否持有读锁
            if (rLock.readLock().isHeldByCurrentThread()) {
                rLock.readLock().unlockAsync();
            }
        }
    },

    /**
     * 写锁
     *
     * 读写锁中的写锁,独占访问共享资源
     * 确保写入操作的原子性和一致性
     */
    WRITE_LOCK {
        @Override
        public boolean lock(LockEntity lock) {
            // 获取读写锁实例的写锁部分
            RReadWriteLock rLock = RedisUtils.getClient().getReadWriteLock(lock.getKey());

            try {
                // 尝试获取写锁
                return rLock.writeLock().tryLock(lock.getWaitTime(), lock.getLeaseTime(), lock.getTimeUnit());
            } catch (Exception e) {
                return false;
            }
        }

        @Override
        public void unlock(LockEntity lock) {
            RReadWriteLock rLock = RedisUtils.getClient().getReadWriteLock(lock.getKey());
            // 检查当前线程是否持有写锁
            if (rLock.writeLock().isHeldByCurrentThread()) {
                rLock.writeLock().unlockAsync();
            }
        }
    };

    /**
     * 尝试获取锁
     *
     * @return 获取锁是否成功
     */
    public abstract boolean lock(LockEntity lock);

    /**
     * 释放锁
     *
     * @param lock 锁实体
     */
    public abstract void unlock(LockEntity lock);

    private LockType() {
    }
}

KeyType.java

java 复制代码
import cn.hutool.core.util.StrUtil;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 锁键类型枚举
 * 定义了分布式锁键的生成策略,包括字符串模板和SpEL表达式两种方式
 *
 */
public enum KeyType {

    /**
     * 字符串键类型
     *
     * 支持直接使用配置的键值,或者根据方法签名和参数自动生成键
     * 当配置的键为空时,会自动拼接方法名和参数作为锁键
     */
    STRING {
        @Override
        public LockEntity resolve(ProceedingJoinPoint joinPoint, DistributeLock lock) {
            // 解析注解属性并创建锁实体
            LockEntity lockEntity = (new LockEntity()).parseLockAnno(lock);
            String key = lock.key();

            // 如果没有显式指定键,则根据方法签名和参数自动生成
            if (StrUtil.isBlank(key)) {
                String methodName = joinPoint.getSignature().toString();
                String argsStr = StrUtil.join(",", joinPoint.getArgs());
                key = StrUtil.concat(true, new CharSequence[]{methodName, "-", argsStr});
            }

            return lockEntity.setKey(key);
        }
    },

    /**
     * SpEL表达式键类型
     *
     * 使用Spring Expression Language解析动态键值
     * 允许在注解中使用复杂的表达式来动态生成锁键
     */
    SPEL {
        @Override
        public LockEntity resolve(ProceedingJoinPoint joinPoint, DistributeLock lock) {
            // 解析注解属性并创建锁实体
            LockEntity lockEntity = (new LockEntity()).parseLockAnno(lock);
            // 使用SpEL表达式解析器计算实际键值
            String key = SpelUtils.parse(joinPoint, lock.key());
            return lockEntity.setKey(key);
        }
    };

    /**
     * 解析锁键
     *
     * 根据不同的键类型策略,从切点和注解信息中解析出具体的锁键
     *
     * @param joinPoint AOP切点,包含目标方法的执行上下文
     * @param lock 分布式锁注解,包含锁的配置信息
     * @return 包含解析后锁键的锁实体
     */
    public abstract LockEntity resolve(ProceedingJoinPoint joinPoint, DistributeLock lock);

    /**
     * 私有构造函数,防止外部实例化
     */
    private KeyType() {
    }
}

BaseSchedule.java

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * 定时任务基类
 * 提供带分布式锁的定时任务执行框架,确保同一时间只有一个线程执行指定的任务
 */
public abstract class BaseSchedule {
    private static final Logger log = LoggerFactory.getLogger(BaseSchedule.class);

    public BaseSchedule() {
    }

    /**
     * 执行带分布式锁的定时任务
     * 使用写锁确保任务的互斥执行,防止多实例或多线程环境下重复执行
     * 锁的租约时间为5秒,单位为秒
     *
     * @param taskName 任务名称,用于日志记录和识别
     * @param cacheKey 缓存键,用于分布式锁的标识,会自动添加"schedule:"前缀
     * @param func 要执行的任务逻辑,实现Runnable接口
     */
    protected void execute(String taskName, String cacheKey, Runnable func) {
        LockType lock = LockType.WRITE_LOCK;
        cacheKey = "schedule:" + cacheKey;
        LockEntity lockEntity = (new LockEntity()).setKey(cacheKey).setWaitTime(0L).setLeaseTime(5L).setTimeUnit(TimeUnit.SECONDS);
        String threadName = Thread.currentThread().getName();
        boolean success = lock.lock(lockEntity);
        if (!success) {
            log.debug("定时任务: {}, 取消执行. {}", taskName, threadName);
        } else {
            try {
                log.debug("定时任务: {}, 开始执行. {}", taskName, threadName);
                func.run();
            } catch (Exception var12) {
                log.error("定时任务: {}, 执行出错. {}", taskName, threadName, var12);
            } finally {
                lock.unlock(lockEntity);
                log.debug("定时任务: {}, 执行结束. {}", taskName, threadName);
            }
        }
    }

}

CronScheduleTask.java

java 复制代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class CronScheduleTask extends BaseSchedule {

    /**
     * 每分钟执行一次
     */
    @Scheduled(cron = "0 * * * * ?")
    public void executeSampleTask() {
        execute("示例定时任务", "sample-task", () -> {
            log.info("执行示例定时任务");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException(e);
            }
            log.info("示例定时任务执行完成");
        });
    }

    /**
     * 每天凌晨2点执行的任务
     */
    @Scheduled(cron = "0 0 2 * * ?")
    public void executeDailyTask() {
        execute("每日定时任务", "daily-task", () -> {
            // 具体业务逻辑
            log.info("执行每日定时任务");
            // 实现具体业务
        });
    }

    /**
     * 每小时执行的任务
     */
    @Scheduled(cron = "0 0 * * * ?")
    public void executeHourlyTask() {
        execute("每小时任务", "hourly-task", () -> {
            log.info("执行每小时任务");
        });
    }
}

五、总结

  • 统一抽象 :通过 [LockType]枚举提供统一的分布式锁接口,封装不同锁类型的实现细节

  • 多样化实现:支持非公平锁、公平锁、多锁、红锁和读写锁等多种锁类型,满足不同业务场景需求

  • 安全性保障 :集成 [Redisson]的成熟分布式锁算法,确保锁的安全性和可靠性

  • 易用性设计 :通过 [LockEntity]统一参数管理,简化锁的使用复杂度

相关推荐
高山上有一只小老虎3 小时前
SpringBoot项目集成thymeleaf实现web
前端·spring boot·后端
麦兜*3 小时前
SpringBoot进阶:深入理解SpringBoot自动配置原理与源码解析
java·spring boot·spring·spring cloud
橘橙黄又青4 小时前
redis复习(2)
数据库·redis·缓存
yangminlei10 小时前
Spring Boot3集成LiteFlow!轻松实现业务流程编排
java·spring boot·后端
qq_3181215910 小时前
互联网大厂Java面试故事:从Spring Boot到微服务架构的技术挑战与解答
java·spring boot·redis·spring cloud·微服务·面试·内容社区
计算机毕设VX:Fegn089510 小时前
计算机毕业设计|基于springboot + vue医院设备管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
txinyu的博客10 小时前
解析业务层的key冲突问题
开发语言·c++·分布式
J_liaty10 小时前
Spring Boot整合Nacos:从入门到精通
java·spring boot·后端·nacos
Mr__Miss10 小时前
保持redis和数据库一致性(双写一致性)
数据库·redis·spring