如今,大家基本都用redission来作为分布式锁的实现方式了。以前的set nx ex方式已经很少见了。
那如何使用redission来做分布式锁呢?
传统使用方式如下:
RLock lock = lockService.getLock(key);
boolean isLocked = false;
try {
isLocked = lock.tryLock();
if (!isLocked) {
log.error("加锁失败 key:{}", key);
return null;
}
//do biz logic
}
finally {
if(isLocked && lock.isHeldByCurrentThread()){
lock.unlock();
}
}
有没有更优雅的方式呢?当然有。见如下代码块
/**
* 同步获取锁,拿不到锁则一直等待
* @param key
* @param lockHandler 接入方可以通过匿名类实现业务逻辑
*/
public void lock(String key, LockHandler lockHandler) {
RLock lock = getLock(key);
lock.lock();
try {
lockHandler.invoke();
}
finally {
//释放锁
lock.unlock();
}
}
其中,LockHandler 就是一个函数式接口(java8出现)。我们可以在此接口的实现类里写对应的业务逻辑即可。
@FunctionalInterface
public interface LockHandler {
/**
* 获取到锁以后的逻辑
*/
void invoke();
}
如此一来,我们使用分布式锁时,只需要关注业务代码即可。
然而,使用时,我们还要考虑具体的业务场景。比如什么时候用lock方法,什么时候用tryLock方法。而且请注意:tryLock 里面有两个时间参数。代码实现如下:
/**
*
* @param key 锁对应的key
* @param waitTime 阻塞时间
* @param leaseTime 锁持有时间 (推荐两个时间都传递)
* @param timeUnit 时间单位
* @param lockHandler 函数式接口实现
* @return 是否获取了锁
*/
public boolean tryLock(String key, long waitTime, long leaseTime,TimeUnit timeUnit, LockHandler lockHandler) {
RLock lock = getLock(key);
// 用于标识是否获取了锁
boolean acquire = false;
try {
// 成功获得锁后返回 true
if (waitTime <= 0L) {
acquire = lock.tryLock();
}
else {
acquire = lock.tryLock(waitTime, leaseTime,timeUnit);
}
if (acquire) {
//获得锁后回调具体的业务逻辑
lockHandler.invoke();
return true;
}
// 没有获得锁
return false;
} catch (InterruptedException e) {
log.error("获取分布式锁失败:{}",e);
//没有获得锁
return false;
}
finally {
if (acquire && lock.isHeldByCurrentThread()) {
// 释放锁
lock.unlock();
}
}
}
其中waitTime是等待锁的时间,而leaseTime表示锁的持有时间。
大家可以根据业务场景选择不同的方式,并配置好相应的时间参数。
分布式锁的功能可以作为框架的一个组件单独实现,这样业务方只需接入这个SDK就可以了。
具体框架组件的建设步骤,可以关注我的专栏:框架的建设思路和组织结构-CSDN博客