一、tryLock()
Redisson 的 tryLock() 方法是 RLock 接口的一部分,这个方法用于尝试获取锁,如果锁当前不可用(即被其他线程或进程持有),则根据不同的重载版本表现出不同的行为。RLock 提供了几种不同的 tryLock() 方法重载版本:
-
无参数版本:
boolean tryLock()这个方法会立即返回,如果锁可用并且当前线程成功获取到锁,它返回
true;如果锁不可用,它立即返回false。 -
等待时间限制版本:
boolean tryLock(long time, TimeUnit unit) throws InterruptedException这个版本的方法尝试在指定的最大时间内获取锁。如果在这段时间内锁变得可用并且当前线程成功获取到锁,它返回
true;如果超时未能获取到锁,则返回false。time参数指定等待时间,而unit是一个TimeUnit枚举值,指定时间单位。 -
等待时间和锁持有时间限制版本:
boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException这个版本不仅指定了获取锁的等待时间(如同第二种版本),还额外指定了一旦获取到锁后,锁可以被持有的时间。如果在
waitTime时间内获取到了锁,并且指定了leaseTime,锁将在leaseTime时间后自动释放(除非手动提前释放)。这有助于防止死锁。 -
非公平锁尝试获取:
boolean tryLock(long waitTime, long leaseTime, TimeUnit unit, boolean fair) throws InterruptedException这个重载版本类似于第三种,但它允许您指定锁的公平性。如果
fair设置为true,则使用公平锁模式,否则使用非公平锁模式。
每种版本的 tryLock() 方法都有其特定的使用场景。选择哪种取决于您的具体需求,比如您是否需要在无法立即获取锁时等待一段时间,以及是否需要在一定时间后自动释放锁等。
二、公平锁和非公平锁
公平锁和非公平锁是同步锁的两种类型,它们在处理线程获取锁的顺序上有所不同:
-
公平锁:
- 公平锁意味着锁的获取顺序遵循线程等待的顺序,即“先来先服务”原则。
- 使用公平锁时,等待最久的线程将优先获得锁。
- 公平锁可能会导致较长的等待时间,因为每次都必须从队列中选择下一个线程。
-
非公平锁:
- 非公平锁不遵循线程等待的顺序。当锁被释放时,任何线程都有机会获取锁,而不考虑等待时间的长短。
- 非公平锁可能会导致某些线程饿死(即永远获取不到锁),但通常其性能高于公平锁,因为它减少了线程切换和队列管理的开销。
根据应用的具体需求和性能考虑,开发者可以选择使用公平锁还是非公平锁。例如,如果确保处理顺序的公平性非常重要,则应选择公平锁;如果更注重吞吐量和性能,则可能更倾向于使用非公平锁。
三、RLock 接口的 lock() 与 tryLock()
在使用 Redisson 的 RLock 和 lock() 方法时,lock() 方法确实提供了一个阻塞式的锁获取机制。这意味着如果锁当前不可用(已被其他线程或进程持有),lock() 方法会等待,直到它能够获取到锁为止。在这种意义上,它可以被视为“自动重试”获取锁,因为调用线程会在锁被释放并且自己成为获取锁的下一个候选者时自动获得锁。
这是如何工作的:
- 当您调用
lock.lock()时,如果锁可用(即没有其他线程持有该锁),那么当前线程将立即获取该锁并继续执行。 - 如果锁不可用(已被其他线程持有),当前线程将阻塞,等待直到锁被释放。这个等待过程可以被看作是一个“自动重试”的过程。
- 一旦锁被释放,等待的线程(或线程之一,如果有多个线程在等待)将获得锁,并继续执行。
需要注意的是,lock() 方法默认情况下可能会无限期地等待。如果您希望在一定时间内无法获取锁时让线程放弃等待,可以使用 tryLock(long waitTime, long leaseTime, TimeUnit unit) 方法,它允许您指定最大等待时间。
例如:
if (lock.tryLock(10, 2, TimeUnit.SECONDS)) {
try {
// 执行业务逻辑
} finally {
lock.unlock();
}
} else {
// 无法在指定时间内获取锁
}
这里,tryLock(10, 2, TimeUnit.SECONDS) 尝试最多等待 10 秒来获取锁,如果在 10 秒内获取到锁,它将持有该锁 2 秒(除非手动提前释放)。如果 10 秒内无法获取锁,
则会返回 false,表示未能获取锁,您可以根据这个返回值来决定接下来的操作。
使用 tryLock 方法可以提供更好的控制,特别是在高并发的环境中,它可以帮助避免线程因长时间等待锁而导致的资源浪费。同时,它也允许您在无法获取锁时快速失败,从而可以采取其他措施,比如重试、记录日志或者返回错误响应。