本文主要介紹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);
}
}
}