org.redisson.api.RLock,是目前较为常见的分布式锁实现方式。我们的目的是实现自动管理锁的获取和释放。
但遗憾的是,RLock并不实现AutoCloseable接口,因此不能直接用在try-with-resources结构中。不过,我们可以通过创建一个包装类或者辅助方法,使得RLock的使用更加符合try-with-resources模式。这样做的好处是使得代码更加简洁,并且能够保证即使发生异常也能够正确释放资源。
1.实现代码
1.1包装类
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import java.util.concurrent.TimeUnit;
/**
* @Description: RLock并不实现AutoCloseable接口,因此不能直接用在try-with-resources结构中。
* 创建一个包装类,使得RLock的使用更加符合try-with-resources模式。这样做的好处是使得代码更加简洁,并且能够保证即使发生异常也能够正确释放资源
**/
@Slf4j
public class AutoCloseableLock implements AutoCloseable{
/**
* 锁定请求
*/
private final String target;
/**
* 要获取的锁。
*/
private final RLock lock;
/**
*锁状态
*/
private final boolean locked;
/**
* 获取锁的等待时长
*/
private static final int WAIT_TIME = 3;
/**
* 占用锁的最大时长
*/
private static final int LEASE_TIME = 10;
public AutoCloseableLock(RLock lock, String target) throws InterruptedException {
this.lock = lock;
// 尝试获取锁,并立即返回结果。如果获取成功,设置锁的自动释放时间。
this.locked = lock.tryLock(WAIT_TIME,LEASE_TIME, TimeUnit.SECONDS);
this.target = target;
}
public boolean isLocked() {
log.info("=====redisson分布式锁,【{}】上锁成功=====",this.target);
return this.locked;
}
@Override
public void close() {
if (this.locked && lock.isHeldByCurrentThread()) {
log.info("=====redisson分布式锁,【{}】开锁成功=====",this.target);
lock.unlock();
}
}
}
1.2参数枚举类
public enum LockEnum {
login("LOGIN", "用户登录请求");
/**
* 锁前缀
*/
private final String prefix;
/**
* 锁请求
*/
private final String target;
LockEnum(String prefix, String target) {
this.prefix = prefix;
this.target = target;
}
public String getPrefix() {
return prefix;
}
public String getTarget() {
return target;
}
}
1.3 类的使用
try (AutoCloseableLock autoLock = new AutoCloseableLock(
redissonClient.getLock(StrUtil.format("{}_{}", LockEnum.login.getPrefix(), username)),
LockEnum.login.getTarget())) {
if (autoLock.isLocked()) {
// 成功获取锁,执行业务逻辑...
} else {
// 获取锁失败的处理逻辑...
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 重新设置中断状态
// 处理中断异常...
}
2设计模式讲解
在这个示例中,AutoCloseableLock包装了一个Lock对象,并确保了在try-with-resources语句结束时自动释放锁,这既体现了资源管理器模式的优势,也借助装饰器模式的理念,为Lock对象增加了自动资源管理的功能。
2.1 资源管理器(Resource Management)模式
资源管理器设计模式的核心思想是确保对于需要手动管理的资源(如文件、数据库连接或锁等),在使用完毕后能够自动释放,以避免资源泄漏。在Java中,try-with-resources语句是这一模式的一个体现,它要求资源实现AutoCloseable或Closeable接口。当try块执行完毕时,无论是正常完成还是因为异常退出,都会自动调用close()方法来释放资源。
AutoCloseableLock类通过实现AutoCloseable接口,使得锁资源可以在try-with-resources语句中自动管理,从而简化了锁的获取和释放过程,减少了编码错误导致的资源泄漏风险。
2.2 装饰器(Decorator)模式
装饰器设计模式允许向一个对象添加新的功能,而不改变其结构。这是通过创建一个包含了原始对象的新对象来实现的,即“装饰”了原始对象。在AutoCloseableLock的上下文中,虽然它的主要目的不是为了添加新功能,但它通过包装Lock对象,并在此基础上添加了自动资源管理的功能,从某种角度来看,也体现了装饰器模式的思想。