1、概述
什么是分布式锁?在分布式系统中,常常需要协调各个系统的动作,保证事务的一致性或者避免重复执行相同操作。如果不同的系统或是同一个系统的不同主机之间需要共享同一资源,那么系统在访问这些资源的时候,往往需要互斥来防止彼此干扰,避免造成各系统的资源不一致,这个时候,便需要使用到分布式锁。Redisson基于redis提供了我们常用的一些锁。
redisson官方发布了redisson-spring-boot-starter
,具体可以参考:gitHub文档
redisson最新依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.10.5</version>
</dependency>
2、特点
- 互斥:锁的最基本特性,分布式锁需要保证不同节点不同线程互斥。
- 死锁: 如果一个线程获得锁,但由于某些原因不能释放锁,致使其他线程永远无法获取锁,形成死锁。分布式锁必须做到避免死锁。
- 性能: 高并发分布式系统中,线程互斥等待可能会造成性能瓶颈,需要开发人员妥善处理。
- 锁特性:分布式锁不能只是加锁,然后一直等待。最好实现如Java Lock的一些功能如:锁判断,超时设置,可重入性等。
3、锁类型
- 可重入锁
可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁。
Redisson的可重入锁RLock
接口继承了java.util.concurrent.locks.Lock
接口,支持锁自动过期
public void ReentrantLock(RedissonClient redisson) {
RLock lock = redisson.getLock("test");
try {
// 加锁
// lock.lock();
// 若没有手动释放锁,10秒钟以后自动解锁
// lock.lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待3秒,上锁以后60秒自动解锁
boolean res = lock.tryLock(3, 60, TimeUnit.SECONDS);
if (res) { //成功
// do something
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 手动解锁
lock.unlock();
}
}
RLock
继承了org.redisson.api.RLockAsync
,支持异步执行
public void AsynReentrantLock(RedissonClient redisson) {
RLock lock = redisson.getLock("test");
try {
// lock.lockAsync();
// lock.lockAsync(10, TimeUnit.SECONDS);
Future<Boolean> res = lock.tryLockAsync(3, 60, TimeUnit.SECONDS);
if (res.get()) {
// do something
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
- 公平锁
加锁前先查看是否有排队等待的线程,有的话优先处理排在前面的线程,原则是先到先得。保证了当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程。
public void FairLock(RedissonClient redisson) {
RLock fairLock = redisson.getFairLock("test");
try {
// fairLock.lock();
// fairLock.lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待3秒,上锁以后60秒自动解锁
boolean res = fairLock.tryLock(3, 60, TimeUnit.SECONDS);
if (res) { //成功
// do something
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
fairLock.unlock();
}
}
- 联锁
RedissonMultiLock
对象可以将多个RLock
关联为一个联锁,每个RLock
对象实例可以来自于不同的Redisson实例。
public void MultiLock(RedissonClient redisson1,RedissonClient redisson2, RedissonClient redisson3){
RLock lock1 = redisson1.getLock("lock1");
RLock lock2 = redisson2.getLock("lock2");
RLock lock3 = redisson3.getLock("lock3");
RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
try {
// 同时加锁lock1 lock2 lock3, 所有的锁都上锁成功才算成功。
lock.lock();
// 尝试加锁,最多等待10秒,上锁以后60秒自动解锁
boolean res = lock.tryLock(10, 60, TimeUnit.SECONDS);
if (res) { //成功
// do something
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
- 红锁
RedissonRedLock
对象实现了RedLock
的加锁算法,其也可以将多个RLock
对象关联为一个红锁,每个RLock
对象实例可以来自于不同的Redisson实例。
public void RedLock(RedissonClient redisson1, RedissonClient redisson2, RedissonClient redisson3) {
RLock lock1 = redisson1.getLock("lock1");
RLock lock2 = redisson2.getLock("lock2");
RLock lock3 = redisson3.getLock("lock3");
RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
try {
// 同时加锁:lock1 lock2 lock3, 红锁在大部分节点上加锁成功就算成功。
lock.lock();
// 尝试加锁,最多等待10秒,上锁以后60秒自动解锁
boolean res = lock.tryLock(10, 60, TimeUnit.SECONDS);
if (res) { //成功
// do something
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
- 读写锁
Redisson的分布式可重入读写锁RReadWriteLock
继承了java.util.concurrent.locks.ReadWriteLock
。
该对象允许同时有多个读取锁,但是最多只能有一个写入锁。
public void ReadLock(RedissonClient redisson){
RReadWriteLock rwlock = redisson.getReadWriteLock("test");
try {
rwlock.readLock().lock();
// 10秒钟以后自动解锁
rwlock.readLock().lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待10秒,上锁以后60秒自动解锁
boolean res = rwlock.readLock().tryLock(10, 60, TimeUnit.SECONDS);
if (res) { //成功
// do something
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwlock.readLock().unlock();
}
}
public void WriteLock(RedissonClient redisson){
RReadWriteLock rwlock = redisson.getReadWriteLock("test");
try {
rwlock.writeLock().lock();
// 10秒钟以后自动解锁
rwlock.writeLock().lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待10秒,上锁以后60秒自动解锁
boolean res = rwlock.writeLock().tryLock(10, 60, TimeUnit.SECONDS);
if (res) { //成功
// do something
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwlock.writeLock().unlock();
}
}
网友评论