原来的分布式锁他锁住的原理在于他返回的布尔值来进行逻辑分支操作,以前之所以不能重入锁的原因在于。在redis的分布式锁中,它的setIfAbsence()方法,限定了。如果该key赋了值,那么后续想要再次为此key赋值的操作都将失败,因此,我们需要可重入锁的就不能采用该方法,所以我们采用一个HashMap的数据格式,里面包含了三值,分别是key、计数器、value,它
可重入的原理在于,当调用该锁的时候,如果该锁存在,那么我就将里面的计数器数值加一,然后手动返回一个True,进行逻辑操作,而释放锁的操作就变更为计数器的数值减一,当计数器为零的时候就释放锁,如果锁不存在就会返回一个false
存储结构:HashMap
图解:
1.客户端请求获取锁时,先使用setnx(key,value)方法尝试获取分布式锁
2.获得锁的线程会在Redis中设置一个计数器count,并将该计数器与当前线程ID绑定。同时,设置过期时间,防止锁永远不被释放。
3.如果其他线程再次请求加锁,则首先判断是否为持有锁的那个线程,如果是,则直接增加count的值。
4.只有当计数器的值减少到0时,即所有持有锁的线程都已经释放它时,该锁才会被释放。
代码例子:
@Service
public class ProductService {
@Autowired
private RedissonClient redissonClient;
/**
* 扣减库存
*/
public void reduceStock(int productId, int quantity) {
String lockKey = "product_" + productId;
// 获取可重入锁对象
RLock lock = redissonClient.getLock(lockKey);
try {
// 尝试加锁,等待时间为10秒,加锁后锁的有效期为30秒
boolean result = lock.tryLock(10, 30, TimeUnit.SECONDS);
if (result) {
// 如果成功获取锁
// 查询当前库存量
int stock = getProductStock(productId);
// 判断库存够不够
if (stock < quantity) {
throw new RuntimeException("库存不足");
}
// 执行扣库存操作
updateProductStock(productId, stock - quantity);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 解锁操作
lock.unlock();
}
}
/**
* 查询商品库存量
*/
private int getProductStock(int productId) {
// TODO 需要连接数据库查询库存量
return 100;
}
/**
* 修改商品库存量
*/
private void updateProductStock(int productId, int stock) {
// TODO 需要连接数据库修改库存量
}
在示例代码中,我们使用RedissonClient获取一个键为 "product_" + productId 的锁对象,并在try块内进行加锁操作,等待10秒后若仍未加锁成功,则抛出异常。此处通过tryLock方法实现了可重入锁的获取,即当前线程对同一把锁可以进行重复加锁和解锁操作。 如果获取锁成功,则进行业务逻辑处理,最后释放锁对象。