李锋镝的博客 - LiFengdi.Com

  • 首页
  • 时间轴
  • 留言
  • 左邻右舍
  • 我的日常
  • 关于我
青衿之志 履践致远
霁月光风 不萦于怀
  1. 首页
  2. 原创
  3. 正文

SpringBoot基于redis的分布式锁的实现(源码)

2019年7月20日 13943点热度 0人点赞 0条评论

分布式锁有很多种实现方式,下面是用redis实现的一个比较简单实用的方式。源码如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 * @author 李锋镝
 * @date Create at 11:33 2018/9/10
 */
@Component
public class DistributedLock {
    /**
     * 获得锁有效时间
     */
    @Value("${lock.timeout:3000}")
    private long lockTimeout;
    @Value("${lock.sleep.interval.time:30}")
    private long sleepIntervalTime;

    private final StringRedisTemplate redisTemplate;

    @Autowired
    public DistributedLock(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 尝试获取锁,立即返回结果
     *
     * @param key 锁key
     * @return boolean
     */
    public boolean tryLock(String key) {
        if (StringUtils.isEmpty(key)) {
            return true;
        }
        return lock(key, lockTimeout, TimeUnit.MILLISECONDS);
    }

    /**
     * 尝试获取锁,立即返回结果,指定锁过期时间
     *
     * @param key key
     * @param time 锁过期时间
     * @param unit 时间单位
     * @return boolean
     */
    public boolean lock(String key, long time, TimeUnit unit) {
        long lockTime = unit.toMillis(time);
        final ValueOperations<String, String> ops = redisTemplate.opsForValue();
        if (ops.setIfAbsent(key, getCacheValue(lockTime))) {
            return true;
        }
        String currentValue = ops.get(key);

        // 如果currentValue为空,说明锁拥有者已经释放掉锁了,可以进行再次尝试
        if (StringUtils.isEmpty(currentValue)) {
            return ops.setIfAbsent(key, getCacheValue(lockTime));
        }

        //判断上一个锁是否到期,到期尝试获取锁
        if (System.currentTimeMillis() >= getExpireTime(currentValue)) {
            //多个线程恰好都到了这里,但是只有一个线程的设置值和当前值相同,它才有权利获取锁
            String oldValue = ops.getAndSet(key, getCacheValue(lockTime));
            return currentValue.equals(oldValue);
        }
        return false;
    }

    /**
     * 尝试获取锁,如果成功,立即返回,如果一直失败,等到超时之后返回
     *
     * @param key     锁key
     * @param timeout 等待时间
     * @param unit    TimeUnit
     * @return boolean
     * @throws InterruptedException InterruptedException
     */
    public boolean tryLock(String key, long timeout, TimeUnit unit) throws InterruptedException {

        long nanosTimeout = unit.toNanos(timeout);

        long lastTime = System.nanoTime();
        do {
            if (tryLock(key)) {
                return true;
            }

            long now = System.nanoTime();
            nanosTimeout -= now - lastTime;
            lastTime = now;

            //响应中断
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }
        } while (nanosTimeout <= 0L);

        return false;
    }

    /**
     * 获取锁,如果成功,立即返回,如果失败,则不停的尝试,直到成功为止
     *
     * @param key 锁key
     * @throws InterruptedException InterruptedException
     */
    public void lock(String key) throws InterruptedException {

        while (true) {
            if (tryLock(key)) {
                return;
            }

            //响应中断
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }
        }
    }


    /**
     * 释放锁
     *
     * @param key key
     */
    public void unlock(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 获取当期线程缓存value
     *
     * @param timeout 超时时间
     * @return 缓存值
     */
    private String getCacheValue(long timeout) {
        return Thread.currentThread().getName() + ";" + String.valueOf(System.currentTimeMillis() + timeout);
    }

    /**
     * 获取过期时间
     *
     * @param cacheValue 缓存值
     * @return 过期时间
     */
    private long getExpireTime(String cacheValue) {
        String[] values = cacheValue.split(";");
        return values.length > 1 ? Long.parseLong(values[1]) : 0L;
    }

}
除非注明,否则均为李锋镝的博客 - LiFengdi.Com原创文章,转载必须以链接形式标明本文链接
本文链接:https://www.lifengdi.com/archives/article/528
标签: JAVA Spring SpringBoot 分布式 分布式锁 架构
最后更新:2019年7月20日

李锋镝

既然选择了远方,便只顾风雨兼程。

打赏 点赞
< 上一篇
下一篇 >
guest
您的姓名(必填)
您的邮箱(必填)
您的站点
guest
您的姓名(必填)
您的邮箱(必填)
您的站点
0 评论
Inline Feedbacks
查看所有评论
支付宝红包

尘世难逢开口笑,菊花须插满头归。

最新 热点 随机
最新 热点 随机
开工啦~ 今晚,回家过年! 图数据库选型:Neo4j、Janus、HugeGraph Redisson分布式锁的watch dog自动续期机制 哀莫大于心死 你好,2023
居家办公了~C# 11 的这个新特性,我愿称之最强!看病难~取药难~~RocketMQ的push消费方式实现详解国庆节过的也很累~~开工啦~
RocketMQ的push消费方式实现详解 CentOS安装docker MySQL语句执行顺序 如何在面试中介绍自己的项目经验 数据库事务的一点简单总结 笑死、腹肌……根本不可能有腹肌的~~
最近评论
dd 发布于 39 分钟前(02月06日) 请问idea2022 myBatiscodehelperpro 3.1.5激活码?
Frankie Bridge 发布于 8 小时前(02月06日) I really like your writing style..Its so easily un...
Frankie Bridge 发布于 2 天前(02月05日) Hi! Just wondering- what template did you use for ...
lyshark 发布于 3 周前(01月18日) 已添加贵站,申请交换友链:) name: LyShark - 孤风洗剑 link: https:...
poetry 发布于 1 个月前(01月05日) 感谢分享
有情链接
  • 志文工作室
  • 临窗旋墨
  • 旧时繁华
  • 城南旧事
  • 强仔博客
  • 林三随笔
  • 徐艺扬的博客
  • 云辰博客
  • 韩小韩博客
  • 知向前端
  • 阿誉的博客
  • 林羽凡
  • 情侣头像
  • 哥斯拉

COPYRIGHT © 2022 lifengdi.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

豫ICP备16004681号-2