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();
        }

        ///


        /// StackExchange.redis锁
        ///

        /// 数据Key
        ///
        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();
        ///


        /// 代码级锁实现锁
        ///

        /// 数据key
        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,他的实现是类似队列的;
所以从实现上述业务效果的性能上来看,代码级锁应该优于不断重试的方式; 

 

你可能感兴趣的:(技术)