mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-09 04:59:21 +08:00
feat(cache/redisson): 新增 RedisLockUtils Redisson 分布式锁工具类
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
}
|
@@ -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 <T> void publish(String name, T msg, Consumer<T> consumer) {
|
||||
RTopic topic = CLIENT.getTopic(name);
|
||||
topic.publish(msg);
|
||||
consumer.accept(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布消息
|
||||
*
|
||||
* @param name 主题名称
|
||||
* @param msg 发送数据
|
||||
*/
|
||||
public static <T> void publish(String name, T msg) {
|
||||
RTopic topic = CLIENT.getTopic(name);
|
||||
topic.publish(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅消息
|
||||
*
|
||||
* @param name 主题名称
|
||||
* @param clazz 消息类型
|
||||
* @param consumer 自定义处理
|
||||
*/
|
||||
public static <T> void subscribe(String name, Class<T> clazz, Consumer<T> consumer) {
|
||||
RTopic topic = CLIENT.getTopic(name);
|
||||
topic.addListener(clazz, (channel, msg) -> consumer.accept(msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置缓存
|
||||
*
|
||||
@@ -104,7 +141,7 @@ public class RedisUtils {
|
||||
/**
|
||||
* 设置缓存
|
||||
* <p>如果键不存在,则不设置</p>
|
||||
*
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true:设置成功;false:设置失败
|
||||
@@ -117,7 +154,7 @@ public class RedisUtils {
|
||||
/**
|
||||
* 设置缓存
|
||||
* <p>如果键不存在,则不设置</p>
|
||||
*
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param duration 过期时间
|
||||
|
Reference in New Issue
Block a user