redis鎖機(jī)制介紹與實例
1 悲觀鎖
執(zhí)行操作前假設(shè)當(dāng)前的操作肯定(或有很大幾率)會被打斷(悲觀)?;谶@個假設(shè),我們在做操作前就會把相關(guān)資源鎖定,不允許自己執(zhí)行期間有其他操作干擾。
Redis不支持悲觀鎖。Redis作為緩存服務(wù)器使用時,以讀操作為主,很少寫操作,相應(yīng)的操作被打斷的幾率較少。不采用悲觀鎖是為了防止降低性能。
2 樂觀鎖
執(zhí)行操作前假設(shè)當(dāng)前操作不會被打斷(樂觀)?;谶@個假設(shè),我們在做操作前不會鎖定資源,萬一發(fā)生了其他操作的干擾,那么本次操作將被放棄。
3. Redis中的鎖策略
Redis采用了樂觀鎖策略(通過watch操作)。樂觀鎖支持讀操作,適用于多讀少寫的情況!
在事務(wù)中,可以通過watch命令來加鎖;使用 UNWATCH可以取消加鎖;
如果在事務(wù)之前,執(zhí)行了WATCH(加鎖),那么執(zhí)行EXEC 命令或 DISCARD 命令后,鎖對自動釋放,即不需要再執(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鍵值對,并返回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對象的鍵值對
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;
}
}
測試類
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這個性質(zhì),可以實現(xiàn)分布式鎖,當(dāng)然設(shè)計一定復(fù)雜一些!
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
相關(guān)文章
Redis?中ZSET數(shù)據(jù)類型命令使用及對應(yīng)場景總結(jié)(案例詳解)
這篇文章主要介紹了Redis?中ZSET數(shù)據(jù)類型命令使用及對應(yīng)場景總結(jié),本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-01-01

