注:文章皆为个人纪录,可用性请以最终结果为准,若有错还请大佬们指出,谢谢!
步骤一:引入依赖
<!--redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.12.2</version>
</dependency>
步骤二:注入RedissonClient对象
import org.redisson.api.RedissonClient;
@Resource
private RedissonClient redissonClient;
步骤三:获取RLock对象
此处我将RedissonClient 封装过一遍,且几乎无特殊处理,可直接将redissonClientLockServiceImpl替换为redissonClient.getLock(“自定义,确保唯一性”);
源码解析:
锁名要确保唯一性,可由业务区分块 + UUID 拼接而成
/** * Returns Lock instance by name. * <p> * Implements a <b>non-fair</b> locking so doesn't guarantees an acquire order by threads. * * @param name - name of object * @return Lock object */ RLock getLock(String name);
RedissonClientLockServiceImpl 类:
/**
* lock(), 拿不到lock就不罢休,不然线程就一直block
*
* @param lockKey 锁的key
*/
@Override
public RLock getLock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock();
return lock;
}
RLock lock = redissonClientLockServiceImpl.getLock(“自定义,确保唯一性”);
步骤四:尝试抢占锁,并执行业务后释放锁
源码解析:
waitTimeout 尝试获取锁的最大等待时间,超过这个值,则认为获取锁失败
leaseTime 锁的持有时间,超过这个时间锁会自动失效(值应设置为大于业务处理的时间,确保在锁有效期内业务能处理完)
TimeUnit unit 指定时间单位
不释放锁会触发Redisson的"看门狗"机制,此处对”看门狗“不做赘述
/** * Tries to acquire the lock with defined <code>leaseTime</code>. * Waits up to defined <code>waitTime</code> if necessary until the lock became available. * * Lock will be released automatically after defined <code>leaseTime</code> interval. * * @param waitTime the maximum time to acquire the lock * @param leaseTime lease time * @param unit time unit * @return <code>true</code> if lock is successfully acquired, * otherwise <code>false</code> if lock is already set. * @throws InterruptedException - if the thread is interrupted */ boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException;
if (lock.tryLock(CostRedis.WAIT_TIMEOUT, CostRedis.LEASE_TIME, TimeUnit.SECONDS)) {
try {
// TODO 业务处理
} catch (Exception e) {
LOGGER.error("初始化任务失败!");
e.printStackTrace();
} finally {
lock.unlock(); // 释放锁
}
} else {
LOGGER.error("获取锁超时,请稍后重试!");
}
具体业务代码示例:
/**
* 通过分布式锁初始化异步导出任务信息
*
* @param taskName 任务名称
* @param user 操作人
* @return 初始化异步导出任务信息
*/
private Map<String, String> initAsyncExportTask(String taskName, BaseUser user) {
Map<String, String> map = new HashMap<>(5);
UUID uuid = UUIDUtils.random();
RLock lock = redissonClientLockServiceImpl.getLock(REDISSON_CLIENT_KEY_PREFIX + uuid.toString().replace("-", ""));
try {
if (lock.tryLock(CostRedis.WAIT_TIMEOUT, CostRedis.LEASE_TIME, TimeUnit.SECONDS)) {
try {
String taskId = LocalDateTime.now().format(FORMATTER) + (int)(Math.random()*(9999-1000+1)+1000) + "000" +(getCurrentTaskTotalCount() + 1);
AsyncImportExportTaskVO taskVO = assignmentAsyncImportExportTask(taskName, taskId, user); // 赋值
boolean isInit = asyncImportExportTaskService.insertTask(taskVO);
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("taskId", taskId);
int id = asyncImportExportTaskService.getTaskInfoByParams(paramMap).get(0).getId();
map.put("taskId", taskId);
map.put("isInit", isInit ? "success" : "fail");
map.put("id", Integer.toString(id));
} catch (Exception e) {
LOGGER.error("初始化任务失败!");
map.put("errorMsg", "初始化任务失败");
e.printStackTrace();
} finally {
lock.unlock(); // 释放锁
}
} else {
LOGGER.error("获取锁超时,请稍后重试!");
map.put("errorMsg", "获取锁超时,请稍后重试!");
}
} catch (InterruptedException e) {
LOGGER.error("线程阻塞,请稍后重试!");
map.put("errorMsg", "线程阻塞,请稍后重试!");
e.printStackTrace();
}
return map;
}
注:文章皆为个人纪录,可用性请以最终结果为准,若有错还请大佬们指出,谢谢!