本篇文章主要講解如何使用Jedis實現(xiàn)一個簡略的分布式鎖的,想了解分布式鎖相關(guān)的內(nèi)容可以看我這篇文章講解的:
http://www.itdecent.cn/p/b3f95f2d146e
下面直接擼代碼:
首先需要一個連接redis的初始化類
package com.zxy.test.jedis.slock;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashMap;
/**
* @description:...
* @author xinyao.zeng
* @date 2019/10/28
* @version 1.0
*/
public class JedisConnectionUtils {
// HashMap
private static JedisPool pool = null;
static {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(1000);
// pool = new JedisPool(poolConfig,"47.74.144.61",6379,500000);
pool = new JedisPool(poolConfig,"192.168.88.139",6379);
}
public static Jedis getJedis(){
return pool.getResource();
}
}
一個獲取鎖和釋放鎖的工具類
package com.zxy.test.jedis.slock;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import java.util.UUID;
/**
* @description:...
* @author xinyao.zeng
* @date 2019/10/28
* @version 1.0
*/
public class DistributeLock {
//獲得鎖
public String acquireLock(String lockName,long acquireTimeout,long lockTimeout) {
String identify = UUID.randomUUID().toString();
String lockKey = "lock:" + lockName;
int locExpire = (int) (lockTimeout / 1000);
Jedis jedis = null;
try{
jedis = JedisConnectionUtils.getJedis();
long end = System.currentTimeMillis() + acquireTimeout;
while (System.currentTimeMillis() < end) {
//設(shè)置成功,代表獲取鎖成功
if (jedis.setnx(lockKey, identify) == 1) {
jedis.expire(lockKey, locExpire); //設(shè)置超時時間
return identify;
}
if (jedis.ttl(lockKey) == -1) {
jedis.expire(lockKey, locExpire);
}
try {
//等待片刻進行獲取鎖的重試
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}finally{
jedis.close();
}
return null;
}
//釋放鎖
public boolean releaseLock(String lockName,String identifier){
System.out.println(lockName+"開始釋放鎖:"+identifier);
String lockKey = "lock:"+lockName;
Jedis jedis = null;
boolean isRelease = false;
try {
jedis = JedisConnectionUtils.getJedis();
while (true) {
//監(jiān)控,保證釋放鎖,不會被打斷
jedis.watch(lockKey);
//判斷是否為同一把鎖
if (identifier.equals(jedis.get(lockKey))) {
//事務(wù)刪除鎖
Transaction transaction = jedis.multi();
transaction.del(lockKey);
if (transaction.exec().isEmpty()) {
continue;
}
//認(rèn)為鎖釋放成功
isRelease = true;
}
//TODO 異常
jedis.unwatch();
break;
}
}finally {
jedis.close();
}
return isRelease;
}
}
測試類如下:
public class Test extends Thread {
@Override
public void run() {
while(true) {
DistributeLock distributeLock = new DistributeLock();
String lock = distributeLock.acquireLock("updateLock", 2000, 5000);
if (lock != null) {
System.out.println(Thread.currentThread().getName() + "成功獲得鎖");
try {
Thread.sleep(1000);
boolean updateLock = distributeLock.releaseLock("updateLock", lock);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}
}
public static void main(String[] args) {
Test test = new Test();
CountDownLatch countDownLatch = new CountDownLatch(1);
/* try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}*/
for(int i=0;i<10;i++){
new Thread(test,"tName"+i).start();
}
// countDownLatch.countDown();
}
}
測試結(jié)果:

lua腳本的使用
在DistributeLock 類中添加該方法,在測試類中使用該方法獲取鎖。
public boolean releaseLockWithLua(String lockName,String identifier){
System.out.println(lockName+"開始釋放鎖:"+identifier);
Jedis jedis=JedisConnectionUtils.getJedis();
String lockKey="lock:"+lockName;
String lua="if redis.call(\"get\",KEYS[1])==ARGV[1] then " +
"return redis.call(\"del\",KEYS[1]) " +
"else return 0 end";
Long rs=(Long) jedis.eval(lua,1,new String[]{lockKey,identifier});
if(rs.intValue()>0){
return true;
}
return false;
}
測試類
public class UnitTest extends Thread{
@Override
public void run() {
while(true){
DistributedLock distributedLock=new DistributedLock();
String rs=distributedLock.acquireLock("updateOrder",
2000,5000);
if(rs!=null){
System.out.println(Thread.currentThread().getName()+"-> 成功獲得鎖:"+rs);
try {
Thread.sleep(1000);
distributedLock.releaseLockWithLua("updateOrder",rs);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}
}
public static void main(String[] args) {
UnitTest unitTest=new UnitTest();
for(int i=0;i<10;i++){
new Thread(unitTest,"tName:"+i).start();
}
}
}
然后就可以執(zhí)行l(wèi)ua腳本了。