栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

redis做分布式锁

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

redis做分布式锁

问题场景:一个简单的修改功能,先去数据库查出要修改的数据,然后再内存中进行修改,修改完再存回去。在单线程中这样的操作没问题,但是在多线程中,由于查询、修改、保存是三个操作,那就会出问题

一、解决思路

第一个进来的线程先进行占位操作,然后去执行业务代码。当第二个线程进来时发现已经有别的线程占位了,就需要等待或稍后再试。在redis中,占位一般有setnx命令,先进来的线程先占位,使用完后再用del指令释放资源

二、使用步骤 1.引入库

代码如下(示例):

        
            redis.clients
            jedis
            3.3.0
            jar
            compile
        
2.建个测试类,代码如下
package com.example.distuibuted;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;

import java.util.Arrays;
import java.util.UUID;


public class LuaTest {
    public static void main(String[] args) {
        //1.构建一个jedis连接池
        JedisPool jedisPool = new JedisPool("填自己的redis安装地址ip,windos就是127.0.0.1", 6379);
        //2.从连接池获取一个jedis连接
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.auth("123456");
            //3.jedis操作
            String ping = jedis.ping();
            System.out.println(ping);
            //4.获取一个随机字符串
            String value = UUID.randomUUID().toString();
            //获取锁
            String k1 = jedis.set("k1", value, new SetParams().nx().ex(5));
            //5.判断是否成功拿到锁
            if (k1 != null && "OK".equals(k1)) {
                //6.业务操作
                jedis.set("set", "业务操作");
                String set = jedis.get("set");
                System.out.println(set);
                //7.释放锁(里面的字符串是lua脚本的id,需要换成自己的,见第三步)
                jedis.evalsha("b8059ba43af6ffe8bed3db65bac35d452f8115d8", Arrays.asList("k1"), Arrays.asList(value));
            } else {
                System.out.println("没拿到锁");
            }
        }


    }
}
3.lua脚本代码

if redis.call("get",KEYS[1])==ARGV[1] then
return redis.call("del".KEYS[1])
else
return 0
end

这里的keys对应着代码中的evalsha方法中的参数(Arrays.asList(“k1”)),argv代表 Arrays.asList(value)。
至于为什么要用lua脚本来实现则是为了解决超时死锁问题。
比如说锁在释放之前出现了异常,那么就会造成死锁的问题,所以就给锁添加了一个过期时间,这样的话即使就防止应用抛出异常导致锁无法及时释放。
但是这时又会引出另一个问题,比如我设置的超时时间是5秒,那么在第二秒时程序发生了异常,而此时锁还未释放,又有第二个线程来访问应用。那么第二个线程执行到第三秒时,第一个线程的锁刚好达到五秒,便会释放。但是释放的却是第二个线程的锁,这就造成了一种紊乱现象。所以为了解决这个问题。我使用的就是SetParams中的方法,使过期时间和获取锁同时执行。另外,为了防止释放锁的过程中出现问题。因此使用了lua脚本。思路就是首先获取一个随机字符串,然后把这个字符串存进jedis中。当释放锁的时候需要传进去一个value,只有这个value相同时才说明第一个线程释放的是自己的锁,而不是另外一个线程的锁。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/932671.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号