Redis锁的简单应用介绍


本文摘自PHP中文网,作者尚,侵删。

其实说多线程修改数据也不合适,毕竟redis服务端是单线程的,所有命令串行执行,只是在客户端并发发送命令的时候,导致串行的命令一些排列问题和网络时间差等造成数据不一致。本文虽然是数字的加减,但是为了说明锁的情况,故意不是用原子命令incr。(推荐:redis视频教程)

先配上一个简易的RedisHelper,一个set值,一个get值,一个设置并发锁,以便在我后面的操作中,你能清楚我究竟做了什么。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

public class RedisHelper

    {

        public RedisClient client = new RedisClient("127.0.0.1", 6379);

        public void Set<T>(string key, T val)

        {

            client.Set(key, val);

        }

        public T Get<T>(string key)

        {

            var result = client.Get<T>(key);

            return result;

        }

        public IDisposable Acquire(string key)

        {

           return  client.AcquireLock(key);

        }

    }

下面看一下并发代码,我只new了两个Thread。两个线程同时想访问同一个key,分别访问五万次,在并发条件下,我们很难保证数据的准确性,请比较输出结果。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

static void Main(string[] args)

        {

            RedisHelper rds = new RedisHelper();

            rds.Set<int>("mykey1", 0);

            Thread myThread1 = new Thread(AddVal);

            Thread myThread2 = new Thread(AddVal);

            myThread1.Start();

            myThread2.Start();

            Console.WriteLine("等待两个线程结束");

            Console.ReadKey();

        }

 

        public static void AddVal()

        {

            RedisHelper rds = new RedisHelper();

            for (int i = 0; i < 50000; i++)

            {

                 

                    int result = rds.Get<int>("mykey1");

                    rds.Set<int>("mykey1", result + 1);

                 

            }

            Console.WriteLine("线程结束,输出" + rds.Get<int>("mykey1"));

        }

1.jpg

是的,和我们单线程,跑两个50000,会输出100000。现在是两个并发线程同时跑在由于并发造成的数据结果往往不是我们想要的。那么如何解决这个问题呢,Redis已经为我们准备好了!

你可以看到我RedisHelper中有个方法是 public IDisposable Acquire(string key)。 也可以看到他返回的是IDisposable,证明我们需要手动释放资源。

方法内部的 AcquireLock正是关键之处,它像redis中索取一把锁头,被锁住的资源,只能被单个线程访问,不会被两个线程同时get或者set,这两个线程一定是交替着进行的,当然这里的交替并不是指你一次我一次,也可能是你多次,我一次,下面看代码。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

static void Main(string[] args)

        {

            RedisHelper rds = new RedisHelper();

            rds.Set<int>("mykey1", 0);

            Thread myThread1 = new Thread(AddVal);

            Thread myThread2 = new Thread(AddVal);

            myThread1.Start();

            myThread2.Start();

            Console.WriteLine("等待两个线程结束");

            Console.ReadKey();

        }

 

        public static void AddVal()

        {

            RedisHelper rds = new RedisHelper();

            for (int i = 0; i < 50000; i++)

            {

                using (rds.Acquire("lock"))

                {

                    int result = rds.Get<int>("mykey1");

                    rds.Set<int>("mykey1", result + 1);

                }

            }

            Console.WriteLine("线程结束,输出" + rds.Get<int>("mykey1"));

        }

可以看到我使用了using,调用我的Acquire方法获取锁。

2.jpg

输出结果最后是100000,正是我们要的正确结果。前面的8W+是因为两个线程之一先执行结束了。

还有,在正式使用的过程中,建议给我们的锁,使用后删除掉,并加上一个过期时间,使用expire。

以免程序执行期间意外退出,导致锁一直存在,今后可能无法更新或者获取此被锁住的数据。

你也可以尝试一下不设置expire,在程序刚开始执行时,关闭console,重新运行程序,并且在redis-cli的操作控制台,get你锁住的值,将会永远获取不到。

所有连接此redis实例的机器,同一时刻,只能有一个获取指定name的锁.

下面是StackExchange.Redis的写法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

var info = "name-"+Environment.MachineName;

            //如果5秒不释放锁 自动释放。避免死锁

            if (db.LockTake("name", info, TimeSpan.FromSeconds(5)))

            {

                try

                {

                    

                }

                catch (Exception ex)

                {

                     

                }

                finally

                {

                    

                    db.LockRelease("name", token);

                }

            }

更多redis知识请关注redis数据库教程栏目。

以上就是Redis锁的简单应用介绍的详细内容,更多文章请关注木庄网络博客

相关阅读 >>

Redis限流的实现方式有几种?

Redis和mongodb选哪个好

为什么Redis是单线程,为什么这么快?

Redis如何做分页

Redis支持哪些数据结构

总结分享一些关于Redis缓存的面试题

memcached与Redis哪个好

Redis实现30分钟未支付取消订单

Redis安装大全涵盖windows、linux、docker

Redis集群和分布式区别

更多相关阅读请进入《Redis》频道 >>


数据库系统概念 第6版
书籍

数据库系统概念 第6版

机械工业出版社

本书主要讲述了数据模型、基于对象的数据库和XML、数据存储和查询、事务管理、体系结构等方面的内容。



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...