使用Redis的分布式Java锁

什么是分布式锁定?

在多线程程序中,不同的线程可能需要访问相同的资源。但是,允许所有线程同时访问资源可能会导致竞争条件,错误和其他意外行为。

为了确保没有两个线程同时访问同一资源并且资源以可预测的顺序进行操作,程序员使用称为的机制。每个线程首先获取锁,对资源进行操作,最后将锁释放到其他线程。

在Java中,出于多种原因,锁定对象通常比使用同步块更灵活。首先,Lock API可以以不同的方式运行,而synchronized块完全包含在一个方法中。

此外,如果线程被阻止,则无法访问同步块。使用Lock,该线程只有在可用时才获取锁。这大大减少了线程等待的时间。此外,当线程正在等待时,可以调用一个方法来中断线程,这在线程等待获取同步块时是不可能的。

分布式锁定意味着您不仅需要考虑多个线程或进程,还需要考虑在不同计算机上运行的不同客户端。这些单独的服务器必须进行协调,以确保在任何给定时间只有其中一个服务器正在使用该资源。

基于Redis的分布式锁定工具

Redisson框架是一个Redis的基于内存数据网格的Java,对于谁需要执行分布式锁定程序员提供了多个对象。下面,我们将讨论每个选项以及它们之间的差异。

1.锁定

RLock接口java.util.concurrent.locks.Lock 在Java中实现  接口。它是一个可重入的锁,这意味着线程可以多次锁定资源。计数器变量记录锁定请求的次数。一旦线程发出足够的解锁请求并且计数器达到0,就会释放资源。

以下简单的代码示例演示了如何在Redisson中创建和启动Lock:

RLock  锁 =  redisson。getLock(“anyLock”);
//最熟悉的锁定方法
锁定。lock();
尝试 {
  ...
} finally {
  锁定。unlock();
}

 

如果获取此锁的Redisson实例崩溃,则锁可能会在此获取状态中永久挂起。为了避免这种情况,Redisson维持一个锁定“看门狗”,当持有锁的Redisson实例仍然存活时,它会延长锁的到期时间。默认情况下,此锁定监视程序的超时为30秒。可以通过Config.lockWatchdogTimeout 设置更改此限制  。

Redisson还允许您在leaseTime获取租约时指定参数。在指定的时间间隔后,锁定将自动释放:

//获取锁定并在10秒后自动释放
 
//如果尚未调用unlock方法
 
锁定。锁(10,TIMEUNIT。SECONDS);
 
//等待100秒,10秒后自动解锁
 
boolean  res  =  lock。的tryLock(10010,TIMEUNIT。SECONDS);
if(res){
   尝试 {
     ...
   } finally {
       锁定。unlock();
   }
}

 

Redisson还为Lock 对象提供了异步/反应/ rxjava2接口  :

RLock  锁 =  redisson。getLock(“anyLock”);
锁定。lockAsync();
...
 
// Reactive Stream(Spring Project Reactor实现)
RLockReactive  lock  =  redissonReactive。getLock(“anyLock”);
Mono < Void >  res  =  锁定。lock();
...
 
// Reactive Stream(RxJava2实现)
RLockReactive  lock  =  redissonRx。getLock(“anyLock”);
可流动的< Void >  res  =  锁定。lock();
...

 

因为RLock实现了  Lock 接口,所以只有拥有锁的线程才能解锁资源。任何其他方面的尝试都将得到满足  IllegalMonitorStateException

2. FairLock

像它的堂兄一样RLockRFairLock 也实现了  java.util.concurrent.locks.Lock 界面。通过使用a   FairLock,您可以保证线程将按照它们请求的顺序获取资源(即“先进先出”队列)。Redisson为在队列中的下一个线程解锁资源之前重启的线程提供了五秒钟的重启。

与此同时  RLocks,创建和启动a  FairLock 是一个简单的过程:

RLock  锁 =  redisson。getFairLock(“anyLock”);
锁定。lock();
尝试 {
  ...
} catch {
  锁定。unlock();
}

 

3. ReadWriteLock

Redisson RReadWriteLock 实现了   java.util.concurrent.locks.ReadWriteLock 界面。在Java中,读/写锁实际上是两个锁的组合:可以由多个线程同时拥有的只读锁,以及一次只能由单个线程拥有的写锁。

创建和启动a的方法RReadWriteLock 如下:

RReadWriteLock  rwlock  =  redisson。getReadWriteLock(“anyRWLock”);
 
rwlock。readLock()。lock();
尝试 {
  ...
} finally {
  rwlock。readLock()。lock();
}
 
rwlock。writeLock()。lock();
尝试 {
  ...
} finally {
  rwlock。writeLock()。lock();
}

 

4. RedLock

RedissonRedLock 对象实现了Redlock锁定算法,以便在Redis中使用分布式锁:

RLock  lock1  =  redissonInstance1。getLock(“lock1”);
 
RLock  lock2  =  redissonInstance2。getLock(“lock2”);
 
RLock  lock3  =  redissonInstance3。getLock(“lock3”);
 
RedissonRedLock  lock  =  new  RedissonRedLock(lock1,lock2,lock3);
 
锁定。lock();
尝试 {
  ...
} finally {
   锁定。unlock();
}

 

在Redlock算法中,我们在单独的计算机或虚拟机上有许多独立的Redis主节点。该算法尝试使用相同的密钥名称和随机值顺序地获取每个实例中的锁。只有当客户端能够比锁定有效的总时间更快地从大多数实例获取锁定时,才会获取锁定。

5. MultiLock

RedissonMultiLock 对象能够将多个单独的RLock 实例组合在一起  并将它们作为单个实体进行管理:

RLock  lock1  =  redissonInstance1。getLock(“lock1”);
 
RLock  lock2  =  redissonInstance2。getLock(“lock2”);
 
RLock  lock3  =  redissonInstance3。getLock(“lock3”);
 
RedissonMultiLock  lock  =  new  RedissonMultiLock(lock1,lock2,lock3);
 
锁定。lock();
尝试 {
  ...
} finally {
  锁定。unlock();
}

 

正如我们在上面的示例中所看到的,每个RLock 对象可能属于不同的Redisson实例。反过来,这可以连接到不同的Redis数据库。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值