李锋镝的博客 - LiFengdi.Com

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

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

2019年7月20日 15606点热度 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
本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: JAVA Spring SpringBoot 分布式 分布式锁 架构
最后更新:2019年7月20日

李锋镝

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

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

但使龙城飞将在,不教胡马度阴山。

最新 热点 随机
最新 热点 随机
hnswlib installation failed 一眨眼就三年了…… redis异常记录 今天,是我的第三十一个生日 回忆是一条没有尽头的路 这样的日子什么时候才是个头
今天,是我的第三十一个生日阳了...开工啦~RocketMQ的push消费方式实现详解国庆节过的也很累~~今天天气很好~心情也不差~
解决Elasticsearch分页查询窗口数据太大问题 封控、封控、再封控,居家、居家、再居家 网易云什么时候能有杰伦的歌…… RocketMQ入门级教程 阿里巴巴的26款超神Java开源项目 减肥四个月~
最近评论
李锋镝 发布于 7 天前(05月22日) 兄弟开玩笑了~
王光卫博客 发布于 7 天前(05月22日) :douyin.19: 博主都在规划下个三年了,我当前还没活好
王光卫博客 发布于 2 周前(05月18日) :douyin.19: 我网站只要有人评论留言,就会出现超负荷,研究了半天也不敢就优化mysql
yeminli çeviri 发布于 1 个月前(04月16日) çeviri bürosu
tercüme 发布于 1 个月前(04月16日) çeviri bürosu
有情链接
  • 志文工作室
  • 临窗旋墨
  • 旧时繁华
  • 城南旧事
  • 强仔博客
  • 林三随笔
  • 徐艺扬的博客
  • 云辰博客
  • 韩小韩博客
  • 知向前端
  • 阿誉的博客
  • 林羽凡
  • 情侣头像
  • 哥斯拉
  • 博客录

COPYRIGHT © 2022 lifengdi.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

豫ICP备16004681号-2