欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Redis SETNX实现分布式锁

程序员文章站 2022-12-22 14:46:44
1、某进程1执行 SETNX lock 以尝试获取锁 2、由于某进程2已获得了锁,所以进程1执行 SETNX lock 返回0,即获取锁失败 3、进程1执行 GET lock 来检测锁是否已超时,如果没超时,则线程等待一段时间,再次检测 4、如果进程1检测到锁已超时,即当前的时间大于键 lock 的 ......

1、某进程1执行 setnx lock 以尝试获取锁

2、由于某进程2已获得了锁,所以进程1执行 setnx lock 返回0,即获取锁失败

3、进程1执行 get lock 来检测锁是否已超时,如果没超时,则线程等待一段时间,再次检测

4、如果进程1检测到锁已超时,即当前的时间大于键 lock 的值,进程1会执行以下操作

getset lock <current unix timestamp + lock timeout + 1>

5、由于 getset 操作在设置键的值的同时,还会返回键的旧值,通过比较键 lock 的旧值是否小于当前时间,可以判断进程是否已获得锁

6、假如另一个进程3也检测到锁已超时,并在进程1之前执行了 getset 操作,那么进程1的 getset 操作返回的是一个大于当前时间的时间戳,这样进程1就不会获得锁而继续等待。注意到,即使进程1接下来将键 lock 的值设置了比进程3设置的更大的值也没影响。

另外,值得注意的是,在进程释放锁,即执行 del lock 操作前,需要先判断锁是否已超时。如果锁已超时,那么锁可能已由其他进程获得,这时直接执行 del lock 操作会导致把其他进程已获得的锁释放掉。

c# code

using system;
using system.threading;
using system.threading.tasks;
using csredis;

namespace redislockdemo
{
    public class csredislock
    {
        private static readonly int _lock_timeout = 40;
        private static readonly string _lock_key = "lock";
        public static void test()
        {
            var rds = new csredisclient("127.0.0.1:6379,password=123456,defaultdatabase=13,poolsize=50,ssl=false");
            redishelper.initialization(rds);

            parallel.for(0, 13, x =>
            {
                if (getlock(_lock_key))
                {
                    console.writeline($"person:{x},线程id:{thread.currentthread.managedthreadid},获得锁 woking");

                    if (datetimeoffset.now.tounixtimemilliseconds() < redishelper.get<long>(_lock_key))
                    {
                        //释放锁
                        redishelper.del(_lock_key);
                    }
                }
                else
                {
                    console.writeline($"person:{x},线程id:{thread.currentthread.managedthreadid},获取锁异常");
                }
            });
            console.writeline();
        }

        private static bool getlock(string key)
        {
            bool getlocked = false;
            try
            {
                while (!getlocked)
                {
                    var now = datetimeoffset.now.tounixtimemilliseconds();
                    var lock_time = now + _lock_timeout + 1;
                    getlocked = redishelper.setnx(key, lock_time);
                    //判断是否获取锁,
                    if (getlocked || now > redishelper.get<long>(key) && now > redishelper.getset<long>(key, lock_time))
                    {
                        getlocked = true;
                    }
                    else
                    {
                        thread.sleep(30);
                    }
                }
            }
            catch (exception ex)
            {
                console.writeline(ex.message);
            }
            return getlocked;
        }
    }
}

相关文档: