From cc8adf6d4e67302a832a2f34841a0e7a616bf007 Mon Sep 17 00:00:00 2001 From: zeekling Date: Sun, 9 Jan 2022 16:39:05 +0800 Subject: [PATCH] redis Distributed Lock --- .../zeekling/redis/lock/DistributedLock.java | 23 ++++++ .../redis/lock/RedisDistributedLockImpl.java | 77 +++++++++++++++++++ .../redis/RedisDistributedLockTest.java | 45 +++++++++++ 3 files changed, 145 insertions(+) create mode 100644 src/main/java/com/zeekling/redis/lock/DistributedLock.java create mode 100644 src/main/java/com/zeekling/redis/lock/RedisDistributedLockImpl.java create mode 100644 src/test/java/com/zeekling/redis/RedisDistributedLockTest.java diff --git a/src/main/java/com/zeekling/redis/lock/DistributedLock.java b/src/main/java/com/zeekling/redis/lock/DistributedLock.java new file mode 100644 index 0000000..ac1199d --- /dev/null +++ b/src/main/java/com/zeekling/redis/lock/DistributedLock.java @@ -0,0 +1,23 @@ +package com.zeekling.redis.lock; + +/** + * 实现的分布式锁 + */ +public interface DistributedLock { + + /** + * 获取锁 + * + * @return 锁的标识 + */ + String lock(); + + /** + * 通过锁的标识释放锁 + * + * @param identify 唯一标识 + * @return 释放锁是否成功 + */ + boolean unlock(String identify); + +} diff --git a/src/main/java/com/zeekling/redis/lock/RedisDistributedLockImpl.java b/src/main/java/com/zeekling/redis/lock/RedisDistributedLockImpl.java new file mode 100644 index 0000000..3c33beb --- /dev/null +++ b/src/main/java/com/zeekling/redis/lock/RedisDistributedLockImpl.java @@ -0,0 +1,77 @@ +package com.zeekling.redis.lock; + +import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.params.SetParams; + +import java.util.Collections; + +/** + * 基于Redis实现的分布式锁 + */ +public class RedisDistributedLockImpl implements DistributedLock { + + + private static final String LOCK_SUCCESS = "OK"; + + private static final Long UNLOCK_SUCCESS = 1L; + + // + private static final String UNLOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; + + private final JedisCluster cluster; + + private final long lockTimeout; + + private final String lockKey; + + public RedisDistributedLockImpl(JedisCluster cluster, String lockKey, long lockTimeout) { + + this.cluster = cluster; + this.lockTimeout = lockTimeout; + this.lockKey = lockKey; + } + + @Override + public String lock() { + long end = System.currentTimeMillis() + lockTimeout; + String requireToken = String.valueOf(System.currentTimeMillis()); + int expireTime = 300 * 1000; + SetParams params = new SetParams().nx().px(expireTime); + while (System.currentTimeMillis() < end) { + try { + String result = cluster.set(lockKey, requireToken, params); + if (LOCK_SUCCESS.equals(result)) { + System.out.println("lock success"); + return requireToken; + } + System.out.println("lock failed trying"); + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + return requireToken; + } + + @Override + public boolean unlock(String identify) { + if (identify == null || identify.trim().length() == 0) { + return false; + } + Object obj = new Object(); + try { + obj = cluster.eval(UNLOCK_SCRIPT, Collections.singletonList(lockKey), Collections.singletonList(identify)); + if (UNLOCK_SUCCESS.equals(obj)) { + System.out.println("release lock success, requestToken:" + identify); + return true; + } + } catch (Exception e) { + e.printStackTrace(); + } + System.out.println("release lock failed, requestToken:" + identify + ", result:" + obj); + return false; + } +} diff --git a/src/test/java/com/zeekling/redis/RedisDistributedLockTest.java b/src/test/java/com/zeekling/redis/RedisDistributedLockTest.java new file mode 100644 index 0000000..bfe9526 --- /dev/null +++ b/src/test/java/com/zeekling/redis/RedisDistributedLockTest.java @@ -0,0 +1,45 @@ +package com.zeekling.redis; + +import com.zeekling.redis.lock.RedisDistributedLockImpl; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.JedisPoolConfig; + +import java.util.HashSet; +import java.util.Set; + +public class RedisDistributedLockTest { + + static int n = 500; + + public static void secKill() { + System.out.println("商品数量:" + --n); + } + + public static void main(String[] args) { + Runnable runnable = () -> { + RedisDistributedLockImpl lock = null; + String unLockIdentify = null; + try { + Set set = new HashSet<>(); + set.add(new HostAndPort("127.0.0.1", 30001)); + JedisPoolConfig config = new JedisPoolConfig(); + JedisCluster cluster = new JedisCluster(set, config); + lock = new RedisDistributedLockImpl(cluster, "test1", 20000); + unLockIdentify = lock.lock(); + System.out.println(Thread.currentThread().getName() + "正在运行"); + secKill(); + } finally { + if (lock != null) { + lock.unlock(unLockIdentify); + } + } + }; + System.out.println("------------------开始--------------"); + for (int i = 0; i < 100; i++) { + Thread t = new Thread(runnable); + t.start(); + } + } + +}