温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Redis分布式Java锁的应用

发布时间:2020-06-17 14:58:02 来源:亿速云 阅读:163 作者:元一 栏目:编程语言

什么是分布式锁?

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

在Java中,由于多种原因,锁定对象通常比使用同步块更灵活。首先,Lock API可以以不同的方法运行,而同步块完全包含在一个方法中。
另外,如果线程被阻止,则无法访问同步的块。使用Lock,该线程将仅在可用时获取锁。这大大减少了线程等待的时间。另外,当线程正在等待时,可以调用一种方法来中断线程,而当线程正在等待获取同步块时,这是不可能的。

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

Redis的分布式Java锁定工具

Redisson框架是用于Java的基于Redis的内存数据网格,可为需要执行分布式锁定的程序员提供多个对象。 下面,我们将讨论每个选项及其之间的区别。

1.锁

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

以下简单代码示例演示了如何在Redisson中创建和初始化Lock:

RLock lock = redisson.getLock("anyLock");
// Most familiar locking method
lock.lock();
try {
  ...
} finally {
  lock.unlock();
}

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

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

// Acquire lock and release it automatically after 10 seconds
// if unlock method hasn't been invoked
lock.lock(10, TimeUnit.SECONDS);
// Wait for 100 seconds and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
   try {
     ...
   } finally {
       lock.unlock();
   }
}

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

RLock lock = redisson.getLock("anyLock");
lock.lockAsync();
...
// Reactive Stream (Spring Project Reactor implementation)
RLockReactive lock = redissonReactive.getLock("anyLock");
Mono<Void> res = lock.lock();
...
// Reactive Stream (RxJava2 implementation)
RLockReactive lock = redissonRx.getLock("anyLock");
Flowable<Void> res = lock.lock();
...

由于RLock实现了Lock接口,因此只有拥有锁的线程才能解锁资源。 否则,任何尝试都会遇到IllegalMonitorStateException。

2. FairLock

与其表兄弟RLock一样,RFairLock也实现了java.util.concurrent.locks.Lock接口。 通过使用FairLock,你可以保证线程将按照请求资源的顺序来获取资源(即``先进先出''队列)。 在为队列中的下一个线程解锁资源之前,Redisson会给已死掉五秒钟的线程重新启动。

与RLocks一样,创建和启动FairLock是一个简单的过程:

RLock lock = redisson.getFairLock("anyLock");
lock.lock();
try {
  ...
} catch {
  lock.unlock();
}

3. 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.lock();
try {
  ...
} finally {
   lock.unlock();
}

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

4.ReadWriteLock

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

创建和初始化RReadWriteLock的方法如下:

RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
rwlock.readLock().lock();
try {
  ...
} finally {
  rwlock.readLock().lock();
}
rwlock.writeLock().lock();
try {
  ...
} finally {
  rwlock.writeLock().lock();
}

5.多重锁

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.lock();
try {
  ...
} finally {
  lock.unlock();
}

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

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI