|
@@ -0,0 +1,232 @@
|
|
|
+package com.zanxiang.common.redis.utils;
|
|
|
+
|
|
|
+import com.zanxiang.common.utils.KeyBuilder;
|
|
|
+import com.zanxiang.common.utils.StringUtils;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.redisson.RedissonMultiLock;
|
|
|
+import org.redisson.api.RLock;
|
|
|
+import org.redisson.api.RedissonClient;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collection;
|
|
|
+import java.util.List;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
+
|
|
|
+/**
|
|
|
+ * <p>
|
|
|
+ * 分布式锁帮助类
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @author zhengwangeng
|
|
|
+ * @since 2020/10/19
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+public final class DistributedLockUtil {
|
|
|
+
|
|
|
+ private static RedissonClient redissonClient;
|
|
|
+
|
|
|
+ private static AtomicBoolean initFlag = new AtomicBoolean(false);
|
|
|
+
|
|
|
+ private static final String KEY_PREFIX = KeyBuilder.build("ZX-GAME", "DISTRIBUTE", "LOCK");
|
|
|
+
|
|
|
+ private DistributedLockUtil() {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void setRedissonClient(RedissonClient client) {
|
|
|
+ if (initFlag.compareAndSet(false, true)) {
|
|
|
+ redissonClient = client;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 非过期锁
|
|
|
+ *
|
|
|
+ * @param key key
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static void lock(String key) {
|
|
|
+ RLock rLock = getLock(key);
|
|
|
+ rLock.lock();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 过期锁
|
|
|
+ *
|
|
|
+ * @param key key
|
|
|
+ * @param keepLockTime 持锁时间
|
|
|
+ * @param timeUnit 时间单位
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static void lock(String key, Long keepLockTime, TimeUnit timeUnit) {
|
|
|
+ if (null == timeUnit) {
|
|
|
+ throw new NullPointerException("timeUnit cant be null!");
|
|
|
+ }
|
|
|
+ RLock rLock = getLock(key);
|
|
|
+ rLock.lock(keepLockTime, timeUnit);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 尝试获取一次非过期锁
|
|
|
+ *
|
|
|
+ * @param key key
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Boolean tryLock(String key) {
|
|
|
+ RLock rLock = getLock(key);
|
|
|
+ return rLock.tryLock();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 尝试在一段时间内,持续的去获取非过期锁
|
|
|
+ *
|
|
|
+ * @param key key
|
|
|
+ * @param tryLockWaitTime 尝试等待时间
|
|
|
+ * @param timeUnit 时间单位
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Boolean tryLock(String key, Long tryLockWaitTime, TimeUnit timeUnit) {
|
|
|
+ if (null == timeUnit) {
|
|
|
+ throw new NullPointerException("timeUnit cant be null!");
|
|
|
+ }
|
|
|
+ RLock rLock = getLock(key);
|
|
|
+ try {
|
|
|
+ if (null != tryLockWaitTime && tryLockWaitTime > 0) {
|
|
|
+ return rLock.tryLock(tryLockWaitTime, timeUnit);
|
|
|
+ } else {
|
|
|
+ return rLock.tryLock();
|
|
|
+ }
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ log.error("在为key:{}尝试获取锁的时候,未知异常!", key, e);
|
|
|
+ log.error(e.getMessage(), e);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 尝试在一段时间内,持续的去获取过期锁
|
|
|
+ *
|
|
|
+ * @param key key
|
|
|
+ * @param leaseTime 锁过期时间
|
|
|
+ * @param tryLockWaitTime 尝试等待时间
|
|
|
+ * @param timeUnit 时间单位
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Boolean tryLock(String key, Long leaseTime, Long tryLockWaitTime, TimeUnit timeUnit) {
|
|
|
+ if (null == timeUnit) {
|
|
|
+ throw new NullPointerException("timeUnit cant be null!");
|
|
|
+ }
|
|
|
+ RLock rLock = getLock(key);
|
|
|
+ try {
|
|
|
+ if (null != tryLockWaitTime && tryLockWaitTime > 0) {
|
|
|
+ if (null != leaseTime && leaseTime > 0) {
|
|
|
+ return rLock.tryLock(tryLockWaitTime, leaseTime, timeUnit);
|
|
|
+ } else {
|
|
|
+ return rLock.tryLock(tryLockWaitTime, timeUnit);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (null != leaseTime && leaseTime > 0) {
|
|
|
+ return rLock.tryLock(0, leaseTime, timeUnit);
|
|
|
+ } else {
|
|
|
+ return rLock.tryLock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ log.error("在为key:{}尝试获取锁的时候,未知异常!", key, e);
|
|
|
+ log.error(e.getMessage(), e);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 释放锁
|
|
|
+ *
|
|
|
+ * @param key
|
|
|
+ */
|
|
|
+ public static void unlock(String key) {
|
|
|
+ RLock rLock = getLock(key);
|
|
|
+ if (rLock.isLocked()) {// 先判断要解锁的 key是否已被锁定(防止锁到期自动消除)
|
|
|
+ if (rLock.isHeldByCurrentThread()) {// 是否被当前线程保持(防止锁到期自动消除后被其它实例或线程加锁)
|
|
|
+ rLock.unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取RLock对象
|
|
|
+ *
|
|
|
+ * @param key
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static RLock getLock(String key) {
|
|
|
+ if (StringUtils.isBlank(key)) {
|
|
|
+ throw new NullPointerException("key can't be null!");
|
|
|
+ }
|
|
|
+ return redissonClient.getLock(KEY_PREFIX + key);
|
|
|
+// return redissonClient.getLock(KeyBuilder.build(KEY_PREFIX, key));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 联锁, 当keys中的每个key都上锁,才说明被锁
|
|
|
+ *
|
|
|
+ * @param keys 锁key值集合
|
|
|
+ * @param leaseTime 锁过期时间
|
|
|
+ * @param waitTime 尝试等待时间
|
|
|
+ * @param timeUnit 时间单位
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Boolean multiLock(Collection<String> keys, Long waitTime, Long leaseTime, TimeUnit timeUnit) {
|
|
|
+ if (CollectionUtils.isEmpty(keys)) {
|
|
|
+ throw new NullPointerException("keys cant be null!");
|
|
|
+ }
|
|
|
+ if (null == timeUnit) {
|
|
|
+ throw new NullPointerException("timeUnit cant be null!");
|
|
|
+ }
|
|
|
+ List<RLock> rLocks = new ArrayList<>(keys.size());
|
|
|
+ for (String key : keys) {
|
|
|
+ rLocks.add(getLock(key));
|
|
|
+ }
|
|
|
+ RedissonMultiLock redissonMultiLock = new RedissonMultiLock(rLocks.toArray(new RLock[keys.size()]));
|
|
|
+ try {
|
|
|
+ if (null != waitTime && waitTime > 0) {
|
|
|
+ if (null != leaseTime && leaseTime > 0) {
|
|
|
+ return redissonMultiLock.tryLock(waitTime, leaseTime, timeUnit);
|
|
|
+ } else {
|
|
|
+ return redissonMultiLock.tryLock(waitTime, timeUnit);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (null != leaseTime && leaseTime > 0) {
|
|
|
+ return redissonMultiLock.tryLock(0, leaseTime, timeUnit);
|
|
|
+ } else {
|
|
|
+ return redissonMultiLock.tryLock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ log.error("在为keys:{}尝试获取联锁的时候,未知异常!", keys, e);
|
|
|
+ log.error(e.getMessage(), e);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解联锁
|
|
|
+ *
|
|
|
+ * @param keys 锁key值集合
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static void multiUnLock(Collection<String> keys) {
|
|
|
+ if (CollectionUtils.isEmpty(keys)) {
|
|
|
+ throw new NullPointerException("keys cant be null!");
|
|
|
+ }
|
|
|
+ List<RLock> rLocks = new ArrayList<>(keys.size());
|
|
|
+ for (String key : keys) {
|
|
|
+ rLocks.add(getLock(key));
|
|
|
+ }
|
|
|
+ RedissonMultiLock redissonMultiLock = new RedissonMultiLock(rLocks.toArray(new RLock[keys.size()]));
|
|
|
+ redissonMultiLock.unlock();
|
|
|
+ }
|
|
|
+}
|