1、Redisson介绍
Redisson 是 java 的 Redis 客户端之一,是 Redis 官网推荐的 java 语言实现分布式锁的项目。Redisson 提供了一些 api 方便操作 Redis。因为本文主要以锁为主,所以接下来我们主要关注锁相关的类,以下是 Redisson
中提供的多样化的锁:
可重入锁(Reentrant Lock) 公平锁(Fair Lock) 联锁(MultiLock)
红锁(RedLock) 读写锁(ReadWriteLock) 信号量(Semaphore) 等等
总之,管你了解不了解,反正 Redisson 就是提供了一堆锁… 也是目前大部分公司使用 Redis 分布式锁最常用的一种方式。
本文中 Redisson 分布式锁的实现是基于 RLock 接口,而 RLock 锁接口实现源码主要是 RedissonLock 这个类,而源码中加锁、释放锁等操作都是使用 Lua 脚本来完成的,并且封装的非常完善,开箱即用。
应用:
@Override
@Transactional(rollbackFor = Exception.class)
public boolean createOrder(String userId, String productId) {
// 如果不加锁,必然超卖
RLock lock = redissonClient.getLock("stock:" + productId);
try {
lock.lock(10, TimeUnit.SECONDS);
int stock = stockService.get(productId).getStockNum();
log.info("剩余库存:{}", stock);
if (stock <= 0) {
return false;
}
String orderNo = UUID.randomUUID().toString().replace("-", "").toUpperCase();
if (stockService.decrease(productId)) {
Order order = new Order();
order.setUserId(userId);
order.setProductId(productId);
order.setOrderNo(orderNo);
Date now = new Date();
order.setCreateTime(now);
order.setUpdateTime(now);
orderDao.save(order);
return true;
}
} catch (Exception ex) {
log.error("下单失败", ex);
} finally {
lock.unlock();
}
return false;
}
去除业务逻辑,加锁框架结构为:
RLock lock = redissonClient.getLock("xxx");
lock.lock();
try {
...
} finally {
lock.unlock();
}
关于 RedLock 中的方法
因为 RLock 本身继承自 Lock 接口,如下分为两部分展示:
public interface RLock extends Lock, RLockAsync {
//----------------------Lock接口方法-----------------------
/**
* 加锁 锁的有效期默认30秒
*/
void lock();
/**
* tryLock()方法是有返回值的,它表示用来尝试获取锁,
* 如果获取成功,则返回true,
* 如果获取失败(即锁已被其他线程获取),则返回false .
*/
boolean tryLock();
/**
* tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,
* 只不过区别在于这个方法在拿不到锁时会等待一定的时间,
* 在时间期限之内如果还拿不到锁,就返回false。
* 如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。
*
* @param time 等待时间
* @param unit 时间单位 小时、分、秒、毫秒等
*/
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
/**
* 解锁
*/
void unlock();
/**
* 中断锁 表示该锁可以被中断 假如A和B同时调这个方法,
* A获取锁,B为获取锁,那么B线程可以通过
* Thread.currentThread().interrupt(); 方法真正中断该线程
*/
void lockInterruptibly();
//----------------------RLock接口方法-----------------------
/**
* 加锁 上面是默认30秒这里可以手动设置锁的有效时间
*
* @param leaseTime 锁有效时间
* @param unit 时间单位 小时、分、秒、毫秒等
*/
void lock(long leaseTime, TimeUnit unit);
/**
* 这里比上面多一个参数,多添加一个锁的有效时间
*
* @param waitTime 等待时间
* @param leaseTime 锁有效时间
* @param unit 时间单位 小时、分、秒、毫秒等
*/
boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException;
/**
* 检验该锁是否被线程使用,如果被使用返回True
*/
boolean isLocked();
/**
* 检查当前线程是否获得此锁(这个和上面的区别就是该方法可以判断是否当前线程获得此锁,而不是此锁是否被线程占有)
* 这个比上面那个实用
*/
boolean isHeldByCurrentThread();
/**
* 中断锁 和上面中断锁差不多,只是这里如果获得锁成功,添加锁的有效时间
* @param leaseTime 锁有效时间
* @param unit 时间单位 小时、分、秒、毫秒等
*/
void lockInterruptibly(long leaseTime, TimeUnit unit);
}