分布式锁Redisson实战解析

注:文章皆为个人纪录,可用性请以最终结果为准,若有错还请大佬们指出,谢谢!

步骤一:引入依赖

<!--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;
    }

注:文章皆为个人纪录,可用性请以最终结果为准,若有错还请大佬们指出,谢谢!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值