本文主要介绍redis分布式锁,要点1、删除时确认锁防止超时误删除锁 2、锁的续签
看代码吧
public class RedisLock {
private static String lockkey = "defalut-lock-key";
private static long locktimeSecond = 30;
private static ConcurrentHashMap<String, WatchDog> threadCache = new ConcurrentHashMap<>();
public static void main(String[] args) {
lock();
try {
Thread.sleep(65000);
} catch (Exception e) {}
unLock();
}
//lock by default keyname & timeout(in second)
public static boolean lock() {
return lock(lockkey, locktimeSecond);
}
//get distibutedLock and start a daemon thread to add ttl
public static boolean lock(String key, long lockTimeSecond) {
String state = "";
try {
state = JedisConfig.jedis.set(key, String.valueOf(Thread.currentThread().getId()), "NX", "EX", lockTimeSecond);
} catch (Exception e) {
e.printStackTrace();
JedisConfig.close();
}
boolean result = state.equals("OK");
if (!result) return result;
WatchDog watchDog = new WatchDog(key, String.valueOf(Thread.currentThread().getId()), 15);
threadCache.put(key, watchDog);
Thread thread = new Thread(watchDog);
thread.setDaemon(true);
thread.start();
return result;
}
//unlock by default keyname
public static void unLock() {
unLock(lockkey);
}
//unlock distributedLock and stop daemon thread
public static void unLock(String key) {
JedisConfig.jedis.eval(LuaScript.checkAndDel(key, String.valueOf(Thread.currentThread().getId())));
WatchDog watchDog = threadCache.get(key);
if (watchDog != null) {
watchDog.stop();
}
}
//watchDog
static class WatchDog implements Runnable {
private String key;
private String value;
private long lockTime;
WatchDog(String key, String value, long lockTime) {
this.key = key;
this.value = value;
this.lockTime = lockTime;
}
private void stop() {
Thread.currentThread().interrupt();
}
@Override
public void run() {
long waitTime = lockTime * 1000 * 2 / 3;
System.out.println("守护线程启动");
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(waitTime);
if ((long) JedisConfig.jedis.eval(LuaScript.checkAndExpire(key, value, lockTime)) == -1) {
System.out.println("当前锁不属于当前线程");
stop();
} else {
System.out.println("续签成功");
}
} catch (InterruptedException ie) {
System.out.println("守护线程中断");
} catch (Exception e) {
System.out.println("执行异常" + e);
}
}
System.out.println("守护线程结束");
}
}
}
zk分布式锁,实现比较简单仅仅是判断锁是否能获取,如果要实现阻塞等待和重试,可以用临时顺序节点,判断当前节点是否是最小的,后一个节点watch前一个,前一个完成了通知下一个。
public class ZkLock {
private static final String lockPath = "/defalut-lock-rootnode";
public static boolean lock() {
return lock(lockPath);
}
public static boolean lock(String lockPath) {
try {
if (Zkconfig.cf.checkExists().forPath(lockPath) == null) {
System.out.println("初始化根节点。。。");
Zkconfig.cf.create().creatingParentsIfNeeded().forPath(lockPath);
}
} catch (Exception e) {
System.out.println("zk初始化异常" + e);
}
//创建临时节点
try {
Zkconfig.cf.create().withMode(CreateMode.EPHEMERAL).forPath(lockPath + "/lock");
System.out.println("获取锁成功");
return true;
} catch (Exception e) {
System.out.println("竞争锁失败" + e);
}
return false;
}
public static void unLock() {
unLock(lockPath);
}
public static void unLock(String lockPath) {
try {
if (Zkconfig.cf.checkExists().forPath(lockPath) == null) {
return;
}
Zkconfig.cf.delete().deletingChildrenIfNeeded().forPath(lockPath);
} catch (Exception e) {
System.out.println("删除锁失败" + e);
}
}
}