在Java中,關(guān)于鎖我想大家都很熟悉。在并發(fā)編程中,我們通過(guò)鎖,來(lái)避免由于競(jìng)爭(zhēng)而造成的數(shù)據(jù)不一致問(wèn)題。通常,我們以synchronized 、Lock來(lái)使用它。
但是Java中的鎖,只能保證在同一個(gè)JVM進(jìn)程內(nèi)中執(zhí)行。如果在分布式集群環(huán)境下呢?
一、分布式鎖
分布式鎖,是一種思想,它的實(shí)現(xiàn)方式有很多。比如,我們將沙灘當(dāng)做分布式鎖的組件,那么它看起來(lái)應(yīng)該是這樣的:
加鎖
在沙灘上踩一腳,留下自己的腳印,就對(duì)應(yīng)了加鎖操作。其他進(jìn)程或者線程,看到沙灘上已經(jīng)有腳印,證明鎖已被別人持有,則等待。
解鎖
把腳印從沙灘上抹去,就是解鎖的過(guò)程。
鎖超時(shí)
為了避免死鎖,我們可以設(shè)置一陣風(fēng),在單位時(shí)間后刮起,將腳印自動(dòng)抹去。
分布式鎖的實(shí)現(xiàn)有很多,比如基于數(shù)據(jù)庫(kù)、memcached、Redis、系統(tǒng)文件、zookeeper等。它們的核心的理念跟上面的過(guò)程大致相同。
二、redis
我們先來(lái)看如何通過(guò)單節(jié)點(diǎn)Redis實(shí)現(xiàn)一個(gè)簡(jiǎn)單的分布式鎖。
1、加鎖
加鎖實(shí)際上就是在redis中,給Key鍵設(shè)置一個(gè)值,為避免死鎖,并給定一個(gè)過(guò)期時(shí)間。
SET lock_key random_value NX PX 5000
值得注意的是:
random_value是客戶端生成的唯一的字符串。
NX代表只在鍵不存在時(shí),才對(duì)鍵進(jìn)行設(shè)置操作。
PX 5000設(shè)置鍵的過(guò)期時(shí)間為5000毫秒。
這樣,如果上面的命令執(zhí)行成功,則證明客戶端獲取到了鎖。
2、解鎖
解鎖的過(guò)程就是將Key鍵刪除。但也不能亂刪,不能說(shuō)客戶端1的請(qǐng)求將客戶端2的鎖給刪除掉。這時(shí)候random_value的作用就體現(xiàn)出來(lái)。
為了保證解鎖操作的原子性,我們用LUA腳本完成這一操作。先判斷當(dāng)前鎖的字符串是否與傳入的值相等,是的話就刪除Key,解鎖成功