本篇文章主要讲解如何使用Jedis实现一个简略的分布式锁的,想了解分布式锁相关的内容可以看我这篇文章讲解的:
https://www.jianshu.com/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) {
//设置成功,代表获取锁成功
if (jedis.setnx(lockKey, identify) == 1) {
jedis.expire(lockKey, locExpire); //设置超时时间
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) {
//监控,保证释放锁,不会被打断
jedis.watch(lockKey);
//判断是否为同一把锁
if (identifier.equals(jedis.get(lockKey))) {
//事务删除锁
Transaction transaction = jedis.multi();
transaction.del(lockKey);
if (transaction.exec().isEmpty()) {
continue;
}
//认为锁释放成功
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();
}
}
测试结果:
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();
}
}
}
然后就可以执行lua脚本了。
网友评论