Redisson——FairLock公平锁
早睡蛋
# FairLock介绍
基于Redis的Redisson分布式可重入公平锁也是实现了java.util.concurrent.locks.Lock
接口的一种RLock
对象。同时还提供了异步(Async) (opens new window)、反射式(Reactive) (opens new window)和RxJava2标准 (opens new window)的接口。它保证了当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程。所有请求线程会在一个队列中排队,当某个线程出现宕机时,Redisson会等待5秒后继续下一个线程,也就是说如果前面有5个线程都处于等待状态,那么后面的线程会等待至少25秒。
# FairLock使用
RLock fairLock = redisson.getFairLock("anyLock");
// 最常见的使用方法
fairLock.lock();
1
2
3
2
3
# FairLock看门狗机制
大家都知道,如果负责储存这个分布式锁的Redis节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout (opens new window)来另行指定。
另外Redisson还通过加锁的方法提供了leaseTime
的参数来指定加锁的时间。超过这个时间后锁便自动解开了。
// 10秒钟以后自动解锁
// 无需调用unlock方法手动解锁
fairLock.lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = fairLock.tryLock(100, 10, TimeUnit.SECONDS);
...
fairLock.unlock();
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# FairLock异步执行
RLock fairLock = redisson.getFairLock("anyLock");
fairLock.lockAsync();
fairLock.lockAsync(10, TimeUnit.SECONDS);
Future<Boolean> res = fairLock.tryLockAsync(100, 10, TimeUnit.SECONDS);
1
2
3
4
2
3
4
# 代码实现FairLock
编写接口代码:
@GetMapping("/test/fair/lock/{id}")
public String testFairLock(@PathVariable("id") Long id) {
stockService.testFairLock(id);
return "hello test fairLock!";
}
1
2
3
4
5
2
3
4
5
编写业务代码:
/**
* 测试公平锁
* @param id
*/
public void testFairLock(Long id) {
RLock fairLock = redissonClient.getFairLock("fairLock");
fairLock.lock();
try {
TimeUnit.SECONDS.sleep(10);
System.out.println("........测试公平锁........"+id);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
fairLock.unlock();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 关于使用非公平锁导致请求多发的问题
假如我们使用的是FairLock,那么不会出现请求多发了一次的问题。当我们使用非公平锁,会出现插队(这是正常的)并且会有一些请求多发了一次,这是Nginx导致的,在Nginx中,对于很久都没有响应的请求,它会帮我们重发一次。
我们只需要修改一下nginx.conf配置文件,把响应时间设置长一点即可:
server {
listen 80;
server_name localhost;
#最大连接时间
proxy_connect_timeout 12000;
#最大发送等待时间
proxy_send_timeout 12000;
#最大接收等待时间
proxy_read_timeout 12000;
location / {
proxy_pass http://ideaProject;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15