Skip to content

Commit 4bbfa83

Browse files
committed
add SpringBoot 集成 redisson 文档
1 parent 1edf88b commit 4bbfa83

File tree

1 file changed

+223
-0
lines changed
  • SpringBoot-Redis-Distributed-Redlock

1 file changed

+223
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
## RedLock 简介
2+
在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段。实现高效的分布式锁有三个属性需要考虑:
3+
```
4+
安全属性:互斥,不管什么时候,只有一个客户端持有锁
5+
效率属性A:不会死锁
6+
效率属性B:容错,只要大多数redis节点能够正常工作,客户端端都能获取和释放锁。
7+
解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
8+
```
9+
Redlock是redis官方提出的实现分布式锁管理器的算法。这个算法会比一般的普通方法更加安全可靠。
10+
Redisson提供了很多种类型的分布式锁和分布式同步器,如下:
11+
```text
12+
- 8.1. 可重入锁(Reentrant Lock) --例子以实现
13+
- 8.2. 公平锁(Fair Lock) --例子以实现
14+
- 8.3. 联锁(MultiLock)
15+
- 8.4. 红锁(RedLock)
16+
- 8.5. 读写锁(ReadWriteLock)
17+
- 8.6. 信号量(Semaphore)
18+
- 8.7. 可过期性信号量(PermitExpirableSemaphore)
19+
- 8.8. 闭锁(CountDownLatch)
20+
```
21+
详情可查看下面的参考链接
22+
### 分布式锁实现
23+
```java
24+
@Component
25+
public class RedisLocker implements DistributedLocker {
26+
27+
private final static String LOCKER_PREFIX = "lock:";
28+
29+
/**
30+
* The Redisson client.
31+
*/
32+
@Autowired
33+
RedissonClient redissonClient;
34+
35+
@Override
36+
public <T> T lock(String resourceName, AcquiredLockWorker<T> worker) throws Exception {
37+
return fairLock(resourceName, worker, 100);
38+
}
39+
40+
@Override
41+
public <T> T tryLock(String resourceName, AcquiredLockWorker<T> worker, int lockTime) throws Exception {
42+
RLock lock = redissonClient.getLock(LOCKER_PREFIX + resourceName);
43+
// (可重入锁)最多等待100秒,锁定后经过lockTime秒后自动解锁
44+
boolean success = lock.tryLock(100, lockTime, TimeUnit.SECONDS);
45+
if (success) {
46+
try {
47+
return worker.invokeAfterLockAcquire();
48+
} finally {
49+
lock.unlock();
50+
}
51+
}
52+
throw new UnableToAcquireLockException();
53+
}
54+
55+
@Override
56+
public <T> T fairLock(String resourceName, AcquiredLockWorker<T> worker, int lockTime) throws Exception {
57+
RLock lock = redissonClient.getFairLock(LOCKER_PREFIX + resourceName);
58+
// (公平锁)最多等待100秒,锁定后经过lockTime秒后自动解锁
59+
boolean success = lock.tryLock(100, lockTime, TimeUnit.SECONDS);
60+
if (success) {
61+
try {
62+
return worker.invokeAfterLockAcquire();
63+
} finally {
64+
lock.unlock();
65+
}
66+
}
67+
throw new UnableToAcquireLockException();
68+
}
69+
70+
}
71+
```
72+
**配置客户端**
73+
```java
74+
@Configuration
75+
public class RedissonConfiguration {
76+
77+
/**
78+
* Gets client.
79+
*
80+
* @return the client
81+
*/
82+
@Bean
83+
public RedissonClient redissonClient() {
84+
//如果是默认本地6379,则可不必配置,否则参照
85+
// https://github.com/redisson/redisson/wiki/2.-%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95 配置
86+
return Redisson.create();
87+
}
88+
}
89+
```
90+
**获取锁后的业务处理**
91+
```java
92+
/**
93+
* 获取锁后需要做的逻辑
94+
*
95+
* @param <T> the type parameter
96+
* @author Liaozihong
97+
*/
98+
public interface AcquiredLockWorker<T> {
99+
/**
100+
* Invoke after lock aquire t.
101+
*
102+
* @return the t
103+
* @throws Exception the exception
104+
*/
105+
T invokeAfterLockAcquire() throws Exception;
106+
}
107+
```
108+
**测试类**
109+
```java
110+
@RestController
111+
@Slf4j
112+
public class RedissonLockTestApi {
113+
/**
114+
* The Distributed locker.
115+
*/
116+
@Autowired
117+
RedisLocker distributedLocker;
118+
119+
/**
120+
* Test redlock string.
121+
* 并发下分布式锁测试API
122+
*
123+
* @return the string
124+
* @throws Exception the exception
125+
*/
126+
@RequestMapping(value = "/redlock")
127+
public String testRedlock() throws Exception {
128+
CountDownLatch startSignal = new CountDownLatch(1);
129+
CountDownLatch doneSignal = new CountDownLatch(5);
130+
// 测试5个并发
131+
for (int i = 0; i < 5; ++i) {
132+
new Thread(new Worker(startSignal, doneSignal)).start();
133+
}
134+
startSignal.countDown(); // let all threads proceed
135+
doneSignal.await();
136+
System.out.println("All processors done. Shutdown connection");
137+
return "redlock";
138+
}
139+
140+
/**
141+
* Worker
142+
* <p/>
143+
* Created in 2018.12.05
144+
* <p/>
145+
*
146+
* @author Liaozihong
147+
*/
148+
class Worker implements Runnable {
149+
private final CountDownLatch startSignal;
150+
private final CountDownLatch doneSignal;
151+
152+
/**
153+
* Instantiates a new Worker.
154+
*
155+
* @param startSignal the start signal
156+
* @param doneSignal the done signal
157+
*/
158+
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
159+
this.startSignal = startSignal;
160+
this.doneSignal = doneSignal;
161+
}
162+
163+
@Override
164+
public void run() {
165+
try {
166+
startSignal.await();
167+
//尝试加锁
168+
distributedLocker.lock("test", new AcquiredLockWorker<Object>() {
169+
170+
@Override
171+
public Object invokeAfterLockAcquire() {
172+
doTask();
173+
return "success";
174+
}
175+
176+
});
177+
} catch (Exception e) {
178+
log.warn("获取锁出现异常", e);
179+
}
180+
}
181+
182+
/**
183+
* Do task.
184+
*/
185+
void doTask() {
186+
System.out.println(Thread.currentThread().getName() + " 抢到锁!");
187+
Random random = new Random();
188+
int _int = random.nextInt(200);
189+
System.out.println(Thread.currentThread().getName() + " sleep " + _int + "millis");
190+
try {
191+
Thread.sleep(_int);
192+
} catch (InterruptedException e) {
193+
e.printStackTrace();
194+
}
195+
System.out.println(Thread.currentThread().getName() + " 释放锁!");
196+
doneSignal.countDown();
197+
}
198+
}
199+
}
200+
```
201+
运行结果:
202+
```text
203+
Thread-26 抢到锁!
204+
Thread-26 sleep 181millis
205+
Thread-26 释放锁!
206+
Thread-25 抢到锁!
207+
Thread-25 sleep 189millis
208+
Thread-25 释放锁!
209+
Thread-27 抢到锁!
210+
Thread-27 sleep 42millis
211+
Thread-27 释放锁!
212+
Thread-29 抢到锁!
213+
Thread-29 sleep 97millis
214+
Thread-29 释放锁!
215+
Thread-28 抢到锁!
216+
Thread-28 sleep 45millis
217+
Thread-28 释放锁!
218+
All processors done. Shutdown connection
219+
```
220+
源码 GitHub:https://github.com/liaozihong/SpringBoot-Learning/tree/master/SpringBoot-Redis-Distributed-Redlock
221+
参考链接:
222+
[如何用Redlock实现分布式锁](https://blog.csdn.net/forezp/article/details/70305336)
223+
[分布式锁和同步器](https://github.com/redisson/redisson/wiki/8.-%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E5%92%8C%E5%90%8C%E6%AD%A5%E5%99%A8)

0 commit comments

Comments
 (0)