redis&zk分佈式鎖

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章