Skip to content

Commit 48783db

Browse files
lishuyanlaCharles7c
authored andcommitted
feat(cache/redisson): 新增 RedisLockUtils Redisson 分布式锁工具类
1 parent 49c804a commit 48783db

File tree

2 files changed

+230
-2
lines changed

2 files changed

+230
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
3+
* <p>
4+
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* http://www.gnu.org/licenses/lgpl.html
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package top.continew.starter.cache.redisson.util;
18+
19+
import org.redisson.api.RLock;
20+
import org.redisson.api.RedissonClient;
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
23+
import top.continew.starter.core.util.SpringUtils;
24+
25+
import java.util.concurrent.TimeUnit;
26+
27+
/**
28+
* Redisson分布式锁 工具类
29+
*
30+
* @author lishuyan
31+
*/
32+
public class RedisLockUtils implements AutoCloseable {
33+
34+
private static final Logger log = LoggerFactory.getLogger(RedisLockUtils.class);
35+
36+
/**
37+
* 默认锁过期时间(毫秒)
38+
*/
39+
private static final long DEFAULT_EXPIRE_TIME = 10000L;
40+
41+
/**
42+
* 默认获取锁超时时间(毫秒)
43+
*/
44+
private static final long DEFAULT_TIMEOUT = 5000L;
45+
46+
/**
47+
* Redisson 客户端
48+
*/
49+
private static volatile RedissonClient CLIENT;
50+
51+
/**
52+
* 锁实例
53+
*/
54+
private final RLock lock;
55+
56+
/**
57+
* 是否成功获取锁
58+
*/
59+
private boolean isLocked;
60+
61+
/**
62+
* 获取Redisson客户端实例
63+
*
64+
* @return RedissonClient实例
65+
*/
66+
private static RedissonClient getClient() {
67+
if (CLIENT == null) {
68+
synchronized (RedisLockUtils.class) {
69+
if (CLIENT == null) {
70+
CLIENT = SpringUtils.getBean(RedissonClient.class, false);
71+
}
72+
}
73+
}
74+
return CLIENT;
75+
}
76+
77+
/**
78+
* 私有构造函数,防止外部实例化
79+
*/
80+
private RedisLockUtils(RLock lock, long expireTime, long timeout, TimeUnit unit) {
81+
this.lock = lock;
82+
try {
83+
this.isLocked = lock.tryLock(timeout, expireTime, unit);
84+
if (isLocked) {
85+
log.debug("获取锁成功,key: {}", lock.getName());
86+
} else {
87+
log.debug("获取锁失败,key: {}", lock.getName());
88+
}
89+
} catch (InterruptedException e) {
90+
Thread.currentThread().interrupt();
91+
log.error("获取锁过程中被中断,key: {}", lock.getName(), e);
92+
}
93+
}
94+
95+
/**
96+
* 尝试获取锁(启用看门狗自动续期机制)
97+
*
98+
* @param key 锁的键
99+
* @param timeout 获取锁的超时时间
100+
* @param unit 时间单位
101+
* @return LockUtils 实例
102+
*/
103+
public static RedisLockUtils tryLockWithWatchdog(String key, long timeout, TimeUnit unit) {
104+
RLock lock = getClient().getLock(key);
105+
// 传入-1表示使用看门狗机制
106+
return new RedisLockUtils(lock, -1, timeout, unit);
107+
}
108+
109+
/**
110+
* 尝试获取锁(启用看门狗自动续期机制,默认时间单位为毫秒)
111+
*
112+
* @param key 锁的键
113+
* @param timeout 获取锁的超时时间(单位:毫秒)
114+
* @return LockUtils 实例
115+
*/
116+
public static RedisLockUtils tryLockWithWatchdog(String key, long timeout) {
117+
return tryLockWithWatchdog(key, timeout, TimeUnit.MILLISECONDS);
118+
}
119+
120+
/**
121+
* 尝试获取锁(启用看门狗自动续期机制,使用默认超时时间)
122+
*
123+
* @param key 锁的键
124+
* @return LockUtils 实例
125+
*/
126+
public static RedisLockUtils tryLockWithWatchdog(String key) {
127+
return tryLockWithWatchdog(key, DEFAULT_TIMEOUT);
128+
}
129+
130+
/**
131+
* 尝试获取锁
132+
*
133+
* @param key 锁的键
134+
* @param expireTime 锁的过期时间
135+
* @param timeout 获取锁的超时时间
136+
* @param unit 时间单位
137+
* @return LockUtils 实例
138+
*/
139+
public static RedisLockUtils tryLock(String key, long expireTime, long timeout, TimeUnit unit) {
140+
RLock lock = getClient().getLock(key);
141+
return new RedisLockUtils(lock, expireTime, timeout, unit);
142+
}
143+
144+
/**
145+
* 尝试获取锁(默认时间单位为毫秒)
146+
*
147+
* @param key 锁的键
148+
* @param expireTime 锁的过期时间(单位:毫秒)
149+
* @param timeout 获取锁的超时时间(单位:毫秒)
150+
* @return LockUtils 实例
151+
*/
152+
public static RedisLockUtils tryLock(String key, long expireTime, long timeout) {
153+
return tryLock(key, expireTime, timeout, TimeUnit.MILLISECONDS);
154+
}
155+
156+
/**
157+
* 尝试获取锁(使用默认过期时间和超时时间)
158+
*
159+
* @param key 锁的键
160+
* @return LockUtils 实例
161+
*/
162+
public static RedisLockUtils tryLock(String key) {
163+
return tryLock(key, DEFAULT_EXPIRE_TIME, DEFAULT_TIMEOUT);
164+
}
165+
166+
/**
167+
* 检查是否成功获取锁
168+
*
169+
* @return true:成功;false:失败
170+
*/
171+
public boolean isLocked() {
172+
return isLocked;
173+
}
174+
175+
/**
176+
* 释放锁
177+
*/
178+
@Override
179+
public void close() {
180+
if (isLocked && lock.isHeldByCurrentThread()) {
181+
try {
182+
lock.unlockAsync().get();
183+
log.debug("释放锁成功,key: {}", lock.getName());
184+
} catch (Exception e) {
185+
log.error("释放锁失败,key: {}", lock.getName(), e);
186+
}
187+
} else {
188+
log.debug("锁未被当前线程持有,无需释放,key: {}", lock.getName());
189+
}
190+
}
191+
}

continew-starter-cache/continew-starter-cache-redisson/src/main/java/top/continew/starter/cache/redisson/util/RedisUtils.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.Map;
2929
import java.util.concurrent.ExecutionException;
3030
import java.util.concurrent.TimeUnit;
31+
import java.util.function.Consumer;
3132

3233
/**
3334
* Redis 工具类
@@ -51,6 +52,42 @@ public static RedissonClient getClient() {
5152
return CLIENT;
5253
}
5354

55+
/**
56+
* 发布消息
57+
*
58+
* @param name 主题名称
59+
* @param msg 发送数据
60+
* @param consumer 自定义处理
61+
*/
62+
public static <T> void publish(String name, T msg, Consumer<T> consumer) {
63+
RTopic topic = CLIENT.getTopic(name);
64+
topic.publish(msg);
65+
consumer.accept(msg);
66+
}
67+
68+
/**
69+
* 发布消息
70+
*
71+
* @param name 主题名称
72+
* @param msg 发送数据
73+
*/
74+
public static <T> void publish(String name, T msg) {
75+
RTopic topic = CLIENT.getTopic(name);
76+
topic.publish(msg);
77+
}
78+
79+
/**
80+
* 订阅消息
81+
*
82+
* @param name 主题名称
83+
* @param clazz 消息类型
84+
* @param consumer 自定义处理
85+
*/
86+
public static <T> void subscribe(String name, Class<T> clazz, Consumer<T> consumer) {
87+
RTopic topic = CLIENT.getTopic(name);
88+
topic.addListener(clazz, (channel, msg) -> consumer.accept(msg));
89+
}
90+
5491
/**
5592
* 设置缓存
5693
*
@@ -104,7 +141,7 @@ public static <T> boolean setIfAbsent(String key, T value, Duration duration) {
104141
/**
105142
* 设置缓存
106143
* <p>如果键不存在,则不设置</p>
107-
*
144+
*
108145
* @param key 键
109146
* @param value 值
110147
* @return true:设置成功;false:设置失败
@@ -117,7 +154,7 @@ public static <T> boolean setIfExists(String key, T value) {
117154
/**
118155
* 设置缓存
119156
* <p>如果键不存在,则不设置</p>
120-
*
157+
*
121158
* @param key 键
122159
* @param value 值
123160
* @param duration 过期时间

0 commit comments

Comments
 (0)