From 48783db422525548d7eec5caba788f8ab53d7bec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=A6=E4=B8=AD=E8=87=AA=E6=9C=89=E9=A2=9C=E5=A6=82?= =?UTF-8?q?=E7=8E=89?= <1206770390@qq.com> Date: Sat, 26 Jul 2025 15:00:48 +0000 Subject: [PATCH] =?UTF-8?q?feat(cache/redisson):=20=E6=96=B0=E5=A2=9E=20Re?= =?UTF-8?q?disLockUtils=20Redisson=20=E5=88=86=E5=B8=83=E5=BC=8F=E9=94=81?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cache/redisson/util/RedisLockUtils.java | 191 ++++++++++++++++++ .../cache/redisson/util/RedisUtils.java | 41 +++- 2 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 continew-starter-cache/continew-starter-cache-redisson/src/main/java/top/continew/starter/cache/redisson/util/RedisLockUtils.java diff --git a/continew-starter-cache/continew-starter-cache-redisson/src/main/java/top/continew/starter/cache/redisson/util/RedisLockUtils.java b/continew-starter-cache/continew-starter-cache-redisson/src/main/java/top/continew/starter/cache/redisson/util/RedisLockUtils.java new file mode 100644 index 00000000..92d48e03 --- /dev/null +++ b/continew-starter-cache/continew-starter-cache-redisson/src/main/java/top/continew/starter/cache/redisson/util/RedisLockUtils.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.starter.cache.redisson.util; + +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import top.continew.starter.core.util.SpringUtils; + +import java.util.concurrent.TimeUnit; + +/** + * Redisson分布式锁 工具类 + * + * @author lishuyan + */ +public class RedisLockUtils implements AutoCloseable { + + private static final Logger log = LoggerFactory.getLogger(RedisLockUtils.class); + + /** + * 默认锁过期时间(毫秒) + */ + private static final long DEFAULT_EXPIRE_TIME = 10000L; + + /** + * 默认获取锁超时时间(毫秒) + */ + private static final long DEFAULT_TIMEOUT = 5000L; + + /** + * Redisson 客户端 + */ + private static volatile RedissonClient CLIENT; + + /** + * 锁实例 + */ + private final RLock lock; + + /** + * 是否成功获取锁 + */ + private boolean isLocked; + + /** + * 获取Redisson客户端实例 + * + * @return RedissonClient实例 + */ + private static RedissonClient getClient() { + if (CLIENT == null) { + synchronized (RedisLockUtils.class) { + if (CLIENT == null) { + CLIENT = SpringUtils.getBean(RedissonClient.class, false); + } + } + } + return CLIENT; + } + + /** + * 私有构造函数,防止外部实例化 + */ + private RedisLockUtils(RLock lock, long expireTime, long timeout, TimeUnit unit) { + this.lock = lock; + try { + this.isLocked = lock.tryLock(timeout, expireTime, unit); + if (isLocked) { + log.debug("获取锁成功,key: {}", lock.getName()); + } else { + log.debug("获取锁失败,key: {}", lock.getName()); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("获取锁过程中被中断,key: {}", lock.getName(), e); + } + } + + /** + * 尝试获取锁(启用看门狗自动续期机制) + * + * @param key 锁的键 + * @param timeout 获取锁的超时时间 + * @param unit 时间单位 + * @return LockUtils 实例 + */ + public static RedisLockUtils tryLockWithWatchdog(String key, long timeout, TimeUnit unit) { + RLock lock = getClient().getLock(key); + // 传入-1表示使用看门狗机制 + return new RedisLockUtils(lock, -1, timeout, unit); + } + + /** + * 尝试获取锁(启用看门狗自动续期机制,默认时间单位为毫秒) + * + * @param key 锁的键 + * @param timeout 获取锁的超时时间(单位:毫秒) + * @return LockUtils 实例 + */ + public static RedisLockUtils tryLockWithWatchdog(String key, long timeout) { + return tryLockWithWatchdog(key, timeout, TimeUnit.MILLISECONDS); + } + + /** + * 尝试获取锁(启用看门狗自动续期机制,使用默认超时时间) + * + * @param key 锁的键 + * @return LockUtils 实例 + */ + public static RedisLockUtils tryLockWithWatchdog(String key) { + return tryLockWithWatchdog(key, DEFAULT_TIMEOUT); + } + + /** + * 尝试获取锁 + * + * @param key 锁的键 + * @param expireTime 锁的过期时间 + * @param timeout 获取锁的超时时间 + * @param unit 时间单位 + * @return LockUtils 实例 + */ + public static RedisLockUtils tryLock(String key, long expireTime, long timeout, TimeUnit unit) { + RLock lock = getClient().getLock(key); + return new RedisLockUtils(lock, expireTime, timeout, unit); + } + + /** + * 尝试获取锁(默认时间单位为毫秒) + * + * @param key 锁的键 + * @param expireTime 锁的过期时间(单位:毫秒) + * @param timeout 获取锁的超时时间(单位:毫秒) + * @return LockUtils 实例 + */ + public static RedisLockUtils tryLock(String key, long expireTime, long timeout) { + return tryLock(key, expireTime, timeout, TimeUnit.MILLISECONDS); + } + + /** + * 尝试获取锁(使用默认过期时间和超时时间) + * + * @param key 锁的键 + * @return LockUtils 实例 + */ + public static RedisLockUtils tryLock(String key) { + return tryLock(key, DEFAULT_EXPIRE_TIME, DEFAULT_TIMEOUT); + } + + /** + * 检查是否成功获取锁 + * + * @return true:成功;false:失败 + */ + public boolean isLocked() { + return isLocked; + } + + /** + * 释放锁 + */ + @Override + public void close() { + if (isLocked && lock.isHeldByCurrentThread()) { + try { + lock.unlockAsync().get(); + log.debug("释放锁成功,key: {}", lock.getName()); + } catch (Exception e) { + log.error("释放锁失败,key: {}", lock.getName(), e); + } + } else { + log.debug("锁未被当前线程持有,无需释放,key: {}", lock.getName()); + } + } +} diff --git a/continew-starter-cache/continew-starter-cache-redisson/src/main/java/top/continew/starter/cache/redisson/util/RedisUtils.java b/continew-starter-cache/continew-starter-cache-redisson/src/main/java/top/continew/starter/cache/redisson/util/RedisUtils.java index b522441f..335e06ad 100644 --- a/continew-starter-cache/continew-starter-cache-redisson/src/main/java/top/continew/starter/cache/redisson/util/RedisUtils.java +++ b/continew-starter-cache/continew-starter-cache-redisson/src/main/java/top/continew/starter/cache/redisson/util/RedisUtils.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; /** * Redis 工具类 @@ -51,6 +52,42 @@ public class RedisUtils { return CLIENT; } + /** + * 发布消息 + * + * @param name 主题名称 + * @param msg 发送数据 + * @param consumer 自定义处理 + */ + public static void publish(String name, T msg, Consumer consumer) { + RTopic topic = CLIENT.getTopic(name); + topic.publish(msg); + consumer.accept(msg); + } + + /** + * 发布消息 + * + * @param name 主题名称 + * @param msg 发送数据 + */ + public static void publish(String name, T msg) { + RTopic topic = CLIENT.getTopic(name); + topic.publish(msg); + } + + /** + * 订阅消息 + * + * @param name 主题名称 + * @param clazz 消息类型 + * @param consumer 自定义处理 + */ + public static void subscribe(String name, Class clazz, Consumer consumer) { + RTopic topic = CLIENT.getTopic(name); + topic.addListener(clazz, (channel, msg) -> consumer.accept(msg)); + } + /** * 设置缓存 * @@ -104,7 +141,7 @@ public class RedisUtils { /** * 设置缓存 *

如果键不存在,则不设置

- * + * * @param key 键 * @param value 值 * @return true:设置成功;false:设置失败 @@ -117,7 +154,7 @@ public class RedisUtils { /** * 设置缓存 *

如果键不存在,则不设置

- * + * * @param key 键 * @param value 值 * @param duration 过期时间