溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Redis中鎖的介紹和使用

發(fā)布時(shí)間:2020-06-21 20:12:47 來(lái)源:億速云 閱讀:203 作者:鴿子 欄目:關(guān)系型數(shù)據(jù)庫(kù)

其實(shí)說(shuō)多線程修改數(shù)據(jù)也不合適,畢竟redis服務(wù)端是單線程的,所有命令串行執(zhí)行,只是在客戶端并發(fā)發(fā)送命令的時(shí)候,導(dǎo)致串行的命令一些排列問(wèn)題和網(wǎng)絡(luò)時(shí)間差等造成數(shù)據(jù)不一致。本文雖然是數(shù)字的加減,但是為了說(shuō)明鎖的情況,故意不是用原子命令incr。

先配上一個(gè)簡(jiǎn)易的RedisHelper,一個(gè)set值,一個(gè)get值,一個(gè)設(shè)置并發(fā)鎖,以便在我后面的操作中,你能清楚我究竟做了什么。

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

下面看一下并發(fā)代碼,我只new了兩個(gè)Thread。兩個(gè)線程同時(shí)想訪問(wèn)同一個(gè)key,分別訪問(wèn)五萬(wàn)次,在并發(fā)條件下,我們很難保證數(shù)據(jù)的準(zhǔn)確性,請(qǐng)比較輸出結(jié)果。

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("等待兩個(gè)線程結(jié)束");
            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("線程結(jié)束,輸出" + rds.Get<int>("mykey1"));
        }

Redis中鎖的介紹和使用

是的,和我們單線程,跑兩個(gè)50000,會(huì)輸出100000。現(xiàn)在是兩個(gè)并發(fā)線程同時(shí)跑在由于并發(fā)造成的數(shù)據(jù)結(jié)果往往不是我們想要的。那么如何解決這個(gè)問(wèn)題呢,Redis已經(jīng)為我們準(zhǔn)備好了!

你可以看到我RedisHelper中有個(gè)方法是 public IDisposable Acquire(string key)。  也可以看到他返回的是IDisposable,證明我們需要手動(dòng)釋放資源。

方法內(nèi)部的 AcquireLock正是關(guān)鍵之處,它像redis中索取一把鎖頭,被鎖住的資源,只能被單個(gè)線程訪問(wèn),不會(huì)被兩個(gè)線程同時(shí)get或者set,這兩個(gè)線程一定是交替著進(jìn)行的,當(dāng)然這里的交替并不是指你一次我一次,也可能是你多次,我一次,下面看代碼。

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("等待兩個(gè)線程結(jié)束");
            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("線程結(jié)束,輸出" + rds.Get<int>("mykey1"));
        }

可以看到我使用了using,調(diào)用我的Acquire方法獲取鎖。

輸出結(jié)果最后是100000,正是我們要的正確結(jié)果。前面的8W+是因?yàn)閮蓚€(gè)線程之一先執(zhí)行結(jié)束了。

還有,在正式使用的過(guò)程中,建議給我們的鎖,使用后刪除掉,并加上一個(gè)過(guò)期時(shí)間,使用expire。

以免程序執(zhí)行期間意外退出,導(dǎo)致鎖一直存在,今后可能無(wú)法更新或者獲取此被鎖住的數(shù)據(jù)。

你也可以嘗試一下不設(shè)置expire,在程序剛開(kāi)始執(zhí)行時(shí),關(guān)閉console,重新運(yùn)行程序,并且在redis-cli的操作控制臺(tái),get你鎖住的值,將會(huì)永遠(yuǎn)獲取不到。

所有連接此redis實(shí)例的機(jī)器,同一時(shí)刻,只能有一個(gè)獲取指定name的鎖.

下面是StackExchange.Redis的寫法

var info = "name-"+Environment.MachineName;
            //如果5秒不釋放鎖 自動(dòng)釋放。避免死鎖
            if (db.LockTake("name", info, TimeSpan.FromSeconds(5)))
            {
                try
                {
                   
                }
                catch (Exception ex)
                {
                    
                }
                finally
                {
                   
                    db.LockRelease("name", token);
                }
            }

以上就是Redis鎖的簡(jiǎn)單應(yīng)用介紹的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注億速云其它相關(guān)文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI