redis鎖機(jī)制介紹與實(shí)例
1 悲觀鎖
執(zhí)行操作前假設(shè)當(dāng)前的操作肯定(或有很大幾率)會(huì)被打斷(悲觀)。基于這個(gè)假設(shè),我們?cè)谧霾僮髑熬蜁?huì)把相關(guān)資源鎖定,不允許自己執(zhí)行期間有其他操作干擾。
Redis不支持悲觀鎖。Redis作為緩存服務(wù)器使用時(shí),以讀操作為主,很少寫操作,相應(yīng)的操作被打斷的幾率較少。不采用悲觀鎖是為了防止降低性能。
2 樂觀鎖
執(zhí)行操作前假設(shè)當(dāng)前操作不會(huì)被打斷(樂觀)?;谶@個(gè)假設(shè),我們?cè)谧霾僮髑安粫?huì)鎖定資源,萬(wàn)一發(fā)生了其他操作的干擾,那么本次操作將被放棄。
3. Redis中的鎖策略
Redis采用了樂觀鎖策略(通過watch操作)。樂觀鎖支持讀操作,適用于多讀少寫的情況!
在事務(wù)中,可以通過watch命令來加鎖;使用 UNWATCH可以取消加鎖;
如果在事務(wù)之前,執(zhí)行了WATCH(加鎖),那么執(zhí)行EXEC 命令或 DISCARD 命令后,鎖對(duì)自動(dòng)釋放,即不需要再執(zhí)行 UNWATCH 了
例子
redis鎖工具類
package com.fly.lock; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class RedisLock { //初始化redis池 private static JedisPoolConfig config; private static JedisPool pool; static { config = new JedisPoolConfig(); config.setMaxTotal(30); config.setMaxIdle(10); pool = new JedisPool(config, "192.168.233.200", 6379); } /** * 給target上鎖 * @param target **/ public static void lock(Object target) { //獲取jedis Jedis jedis = pool.getResource(); //result接收setnx的返回值,初始值為0 Long result= 0L; while (result < 1) { //如果target在redis中已經(jīng)存在,則返回0;否則,在redis中設(shè)置target鍵值對(duì),并返回1 result = jedis.setnx(target.getClass().getName() + target.hashCode(), Thread.currentThread().getName()); } jedis.close(); } /** * 給target解鎖 * @param target **/ public static void unLock(Object target) { Jedis jedis = pool.getResource(); //刪除redis中target對(duì)象的鍵值對(duì) Long del = jedis.del(target.getClass().getName() + target.hashCode()); jedis.close(); } /** * 嘗試給target上鎖,如果鎖成功返回true,如果鎖失敗返回false * @param target * @return **/ public static boolean tryLock(Object target) { Jedis jedis = pool.getResource(); Long row = jedis.setnx(target.getClass().getName() + target.hashCode(), "true"); jedis.close(); if (row > 0) { return true; } return false; } }
測(cè)試類
package com.fly.test; import com.fly.lock.RedisLock; class Task { public void doTask() { //上鎖 RedisLock.lock(this); System.out.println("當(dāng)前線程: " + Thread.currentThread().getName()); System.out.println("開始執(zhí)行: " + this.hashCode()); try { System.out.println("doing..."); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("完成: " + this.hashCode()); //解鎖 RedisLock.unLock(this); } } public class Demo { public static void main(String[] args) { Task task = new Task(); Thread[] threads = new Thread[5]; for (Thread thread : threads) { thread = new Thread(()->{ task.doTask(); }); thread.start(); } } }
輸出結(jié)果:
----------------------------------------------
當(dāng)前線程: Thread-0
開始執(zhí)行: 2081499965
doing...
完成: 2081499965
----------------------------------------------
當(dāng)前線程: Thread-2
開始執(zhí)行: 2081499965
doing...
完成: 2081499965
----------------------------------------------
當(dāng)前線程: Thread-1
開始執(zhí)行: 2081499965
doing...
完成: 2081499965
----------------------------------------------
當(dāng)前線程: Thread-4
開始執(zhí)行: 2081499965
doing...
完成: 2081499965
----------------------------------------------
當(dāng)前線程: Thread-3
開始執(zhí)行: 2081499965
doing...
完成: 2081499965
去掉redis鎖后,執(zhí)行結(jié)果:
----------------------------------------------
----------------------------------------------
當(dāng)前線程: Thread-2
開始執(zhí)行: 1926683415
----------------------------------------------
當(dāng)前線程: Thread-1
doing...
當(dāng)前線程: Thread-0
----------------------------------------------
當(dāng)前線程: Thread-3
開始執(zhí)行: 1926683415
doing...
開始執(zhí)行: 1926683415
doing...
----------------------------------------------
開始執(zhí)行: 1926683415
doing...
當(dāng)前線程: Thread-4
開始執(zhí)行: 1926683415
doing...
完成: 1926683415
完成: 1926683415
完成: 1926683415
完成: 1926683415
完成: 1926683415
Process finished with exit code 0
利用redis這個(gè)性質(zhì),可以實(shí)現(xiàn)分布式鎖,當(dāng)然設(shè)計(jì)一定復(fù)雜一些!
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
相關(guān)文章
Redis的使用模式之計(jì)數(shù)器模式實(shí)例
這篇文章主要介紹了Redis的使用模式之計(jì)數(shù)器模式實(shí)例,本文講解了匯總計(jì)數(shù)器、按時(shí)間匯總的計(jì)數(shù)器、速度控制、使用 Hash 數(shù)據(jù)類型維護(hù)大量計(jì)數(shù)器等內(nèi)容,需要的朋友可以參考下2015-03-03Redis鍵值設(shè)計(jì)的具體實(shí)現(xiàn)
本文主要介紹了Redis鍵值設(shè)計(jì)的具體實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06redis安裝和配置_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了redis安裝和配置,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08K8S部署Redis(單機(jī)、集群)的超詳細(xì)步驟
redis是一款基于BSD協(xié)議,開源的非關(guān)系型數(shù)據(jù)庫(kù)(nosql數(shù)據(jù)庫(kù))這篇文章主要給大家介紹了關(guān)于K8S部署Redis(單機(jī)、集群)的超詳細(xì)步驟,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-05-05