StackExchange.Redis加锁机制实例

1、redis下载安装 

Github下载地址:https://github.com/MicrosoftArchive/redis/releases

安装过程不做写明

1、VS引用StackExchange.Redis

通过“工具”=》“库程序包管理器”=》“程序包管理器控制台”

pm>Install-Package StackExchange.Redis -Version 1.2.5

也可通过vs中NuGet获取--(不建议此方式,因为你所用的.net freamwork版本不一定一直,可用过https://www.nuget.org/packages/StackExchange.Redis这个redis官网查看所用freamwork版本对应的redis版本,用控制台添加引用)

using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication5
{
    class Program
    {
        static ConnectionMultiplexer redis;
        static IDatabase _db;
        static RedisValue Token = Environment.MachineName;
        static void Main(string[] args)
        {
            var options = ConfigurationOptions.Parse("localhost");
            options.AllowAdmin = true;
            redis = ConnectionMultiplexer.Connect(options);
            _db = redis.GetDatabase();

            //未使用锁  2个线程同时对一个数据进行加操作
            for (var i = 0; i < 2; i++)
            {
                var key = "key";
                Task.Factory.StartNew((index) =>
                {
                    for (var j = 0; j < 100; j++)
                    {
                        var tmp = _db.StringGet(key);
                        var data = 0;
                        int.TryParse(tmp, out data);
                        _db.StringSet(key, (data + 1).ToString(), TimeSpan.FromSeconds(5));
                    }
                    Console.WriteLine("[未锁]-线程" + (Convert.ToInt32(index) + 1) + "值为:" + _db.StringGet(key));
                }, i);
            }

            //使用第三方锁
            for (var i = 0; i < 2; i++)
            {
                Task.Factory.StartNew((index) =>
                {
                    var key = "key2";
                    for (var j = 0; j < 100; j++)
                    {
                        while (true)
                        {
                            if (StringLockToUpdate(key))
                                break;
                        }
                    }
                    Console.WriteLine("[StackExchange锁]-线程" + (Convert.ToInt32(index) + 1) + "值为:" + _db.StringGet(key));
                }, i);
            }

            //使用自己写的代码级锁
            for (var i = 0; i < 2; i++)
            {
                var key = "key3";
                Task.Factory.StartNew((index) =>
                {
                    for (var k = 0; k < 100; k++)
                    {
                        StringLockToUpdateByNormalLock(key);
                    }
                    Console.WriteLine("[代码级锁]-线程" + (Convert.ToInt32(index) + 1) + "值为:" + _db.StringGet(key));
                }, i);
            }
            Console.WriteLine("完成");
            Console.ReadKey();
        }

        /// <summary>
        /// StackExchange.redis锁
        /// </summary>
        /// <param name="key">数据Key</param>
        /// <returns></returns>
        static bool StringLockToUpdate(string key)
        {
            var flag = false;
            //设置timespan避免死锁,“LockKey”为锁的名字,共同操作时此处唯一
            if (_db.LockTake("LockKey", Token, TimeSpan.FromSeconds(5)))
            {
                try
                {
                    var tmp = _db.StringGet(key);
                    var data = 0;
                    int.TryParse(tmp, out data);
                    _db.StringSet(key, data + 1, TimeSpan.FromSeconds(5));
                    flag = true;
                }
                catch (Exception)
                { 
                    var b = string.Empty;
                }
                finally
                {
                    _db.LockRelease("LockKey", Token);
                }
            }
            return flag;
        }


        static object myLock = new object();
        /// <summary>
        /// 代码级锁实现锁
        /// </summary>
        /// <param name="key">数据key</param>
        static void StringLockToUpdateByNormalLock(string key)
        {
            lock (myLock)
            {
                var tmp = _db.StringGet(key);
                var data = 0;
                int.TryParse(tmp, out data);
                _db.StringSet(key, data + 1, TimeSpan.FromSeconds(5));
            }
        }
    }

}

未使用锁的情况下,两个线程同时对同一个redis值进行变更,最终值无法按照我们预期保证数据准确。
代码级锁和StackExchange锁都实现了我们预期的效果;
根据业务需要,使用StackExchange锁或代码级锁均可实现锁效果。

StackExchange锁和代码级锁都实现了同样的效果
StackExchange是通过不断重试(While)来实现每一次每一次循环的操作都有效执行;
代码级锁中使用了Lock,他的实现是类似队列的;
所以从实现上述业务效果的性能上来看,代码级锁应该优于不断重试的方式; 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这个月太忙没时间看C++

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值