侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

redis分布式锁如何实现原理

Redis  /  管理员 发布于 7年前   244

分布式锁,是控制分布式系统之间同步访问共享资源的一种方式。

在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

使用setnx、getset、expire、del这4个redis命令实现 (推荐学习:Redis视频教程)

setnx 是『SET if Not eXists』(如果不存在,则 SET)的简写。 命令格式:SETNX key value;使用:只在键 key 不存在的情况下,将键 key 的值设置为 value 。若键 key 已经存在, 则 SETNX 命令不做任何动作。返回值:命令在设置成功时返回 1 ,设置失败时返回 0 。

getset 命令格式:GETSET key value,将键 key 的值设为 value ,并返回键 key 在被设置之前的旧的value。返回值:如果键 key 没有旧值, 也即是说, 键 key 在被设置之前并不存在, 那么命令返回 nil 。当键 key 存在但不是字符串类型时,命令返回一个错误。

expire 命令格式:EXPIRE key seconds,使用:为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。返回值:设置成功返回 1 。 当 key 不存在或者不能为 key 设置生存时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 key 的生存时间),返回 0 。

del 命令格式:DEL key [key …],使用:删除给定的一个或多个 key ,不存在的 key 会被忽略。返回值:被删除 key 的数量。

Redis实现分布式锁的原理:

1.通过setnx(lock_timeout)实现,如果设置了锁返回1, 已经有值没有设置成功返回0

2.死锁问题:通过实践来判断是否过期,如果已经过期,获取到过期时间get(lockKey),然后getset(lock_timeout)判断是否和get相同,相同则证明已经加锁成功,因为可能导致多线程同时执行getset(lock_timeout)方法,这可能导致多线程都只需getset后,对于判断加锁成功的线程, 再加expire(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS)过期时间,防止多个线程同时叠加时间,导致锁时效时间翻倍

redis-8.jpg代码:

/** * @author yaoxin * @date 2018/8/13下午5:04 */public class RedisLockTest {     public static final String url = "jdbc:mysql://127.0.0.1:3306/ly?characterEncoding=UTF-8";    public static final String name = "com.mysql.jdbc.Driver";    public static final String user = "root";    public static final String password = "";     public static void main(String[] args) {         Integer count = 50;        while (count > 0) {count--;new Thread(new Runnable() {    @Override    public void run() {        Jedis jedis = new Jedis("127.0.0.1", 6379);        jedis.auth("1234");        String lock = lock(jedis);        if (lock != null) {Statement statement = null;Connection conn = null;ResultSet resultSet = null;try {    Class.forName(name);// 指定连接类型    conn = DriverManager.getConnection(url, user, password);// 获取连接    statement = conn.createStatement();// 准备执行语句    String querySql = "SELECT id,name,count FROM production WHERE id=2";    resultSet = statement.executeQuery(querySql);    int count = 0;    while (resultSet.next()) {        System.out.println(Thread.currentThread().getName() + "抢到了锁 id: " + resultSet.getString("id")    + " name: " + resultSet.getString("name")    + " count: " + resultSet.getString("count"));        count = Integer.valueOf(resultSet.getString("count"));    }    String updateSql = "UPDATE production SET count=" + (count - 1)+ " WHERE id=2";    int rows = statement.executeUpdate(updateSql);    if (rows > 0) {        System.out.println("更新成功" + Thread.currentThread().getName() + "  库存剩余:" + (count - 1));        System.out.println(Thread.currentThread().getName() + " === > >开始解锁");        boolean unlock = unlock(jedis, lock);        if (unlock)System.out.println(Thread.currentThread().getName() + " === > >解锁成功");    } else {        System.out.println("更新失败" + Thread.currentThread().getName());    }} catch (Exception e) {    e.printStackTrace();} finally {    try {        if (conn != null)conn.close();        if (statement != null)statement.close();        if (resultSet != null)resultSet.close();    } catch (Exception e) {        e.printStackTrace();    }}        }    }}, "线程" + count).start();        }    }     public static String lock(Jedis jedis) {        try {while (true) {    String lockTime = Long.valueOf(jedis.time().get(0)) + 5 + "";    if (jedis.setnx("lock", lockTime) == 1) {        jedis.expire("lock", 5);        return lockTime;    }    String lock = jedis.get("lock");    if (!StringUtils.isEmpty(lock) && Long.valueOf(lock) < Long.valueOf(jedis.time().get(0))) {        String oldLockTime = jedis.getSet("lock", lockTime);        if (!StringUtils.isEmpty(oldLockTime) && oldLockTime.equals(lock)) {return lockTime;        }    }    Thread.sleep(100);}        } catch (Exception e) {e.printStackTrace();        }        return null;    }     public static boolean unlock(Jedis jedis, String lockTag) {        if (lockTag.equals(jedis.get("lock"))) {jedis.del("lock");return true;        }        return false;    } }

运行结果如下图:

redis-9.jpg

更多Redis相关技术文章,请访问Redis入门教程栏目进行学习!

以上就是redis分布式锁如何实现原理的详细内容,更多请关注其它相关文章!


  • 上一条:
    redis如何存储list
    下一条:
    redis如何保证数据一致性
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在Redis中能实现的功能、常见应用介绍(0个评论)
    • 2024年Redis面试题之一(0个评论)
    • 在redis缓存常见出错及解决方案(0个评论)
    • 在redis中三种特殊数据类型:地理位置、基数(cardinality)估计、位图(Bitmap)使用场景介绍浅析(2个评论)
    • Redis 删除 key用 del 和 unlink 有啥区别?(1个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-12
    • 2020-03
    • 2020-05
    • 2021-04
    • 2022-03
    • 2022-05
    • 2022-08
    • 2023-02
    • 2023-04
    • 2023-07
    • 2024-01
    • 2024-02
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客