diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java index 115a04bb75b4857004c076f9cf2a82ef13021cc5..79aaa5c171228099ddbfe4f6c31b18d3e4aadc0f 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java @@ -91,8 +91,9 @@ public class CacheStringAspect { // 失效时间控制 Consumer cachePut = prodCachePutFunction(valueOperations, key, cachedAnnotation.ttl(), cachedAnnotation.timeUnit()); - return cached(new CachedOps(point, lockKey, cacheQuery, cachePut, method.getGenericReturnType())); - + int retryCount = cachedAnnotation.retryCount(); + return cached( + new CachedOps(point, lockKey, cacheQuery, cachePut, method.getGenericReturnType(), retryCount)); } // 缓存更新处理 @@ -176,7 +177,7 @@ public class CacheStringAspect { ops.cachePut().accept(cacheValue); } return cacheValue; - }).onLockFail(cacheQuery).lock(); + }).onLockFail(cacheQuery).retryCount(ops.retryCount()).lock(); // 自旋时间内未获取到锁,或者数据库中数据为空,返回null if (cacheData == null || ops.nullValue(cacheData)) { return null; diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java index 793a4b139971b278e337c52103900c4c737aabe1..98da17d8e7e77806c341eb545c8a89d7585fc6c3 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java @@ -35,4 +35,10 @@ public @interface Cached { */ TimeUnit timeUnit() default TimeUnit.SECONDS; + /** + * 锁竞争失败时的重试次数 小于0: 无限重试 等于0: 不重试 大于0: 重试次数 + * @return + */ + int retryCount() default 5; + } diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/DistributedLock.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/DistributedLock.java index 9670f32d25f39d3412273ea50f4d4f7a9a227653..00a17011a5bd2e1333b09440afec18cee1ead770 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/DistributedLock.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/DistributedLock.java @@ -1,5 +1,6 @@ package com.hccake.ballcat.common.redis.lock; +import cn.hutool.core.thread.ThreadUtil; import com.hccake.ballcat.common.redis.lock.function.ExceptionHandler; import com.hccake.ballcat.common.redis.lock.function.ThrowingExecutor; import org.springframework.util.Assert; @@ -24,6 +25,8 @@ public final class DistributedLock implements Action, StateHandler { TimeUnit timeUnit; + int retryCount; + ThrowingExecutor executeAction; UnaryOperator successAction; @@ -71,12 +74,18 @@ public final class DistributedLock implements Action, StateHandler { return this; } + @Override + public StateHandler retryCount(int retryCount) { + this.retryCount = retryCount; + return this; + } + @Override public T lock() { String requestId = UUID.randomUUID().toString(); + boolean exResolved = false; if (Boolean.TRUE.equals(CacheLock.lock(this.key, requestId, this.timeout, this.timeUnit))) { T value = null; - boolean exResolved = false; try { value = executeAction.execute(); this.result = value; @@ -92,7 +101,13 @@ public final class DistributedLock implements Action, StateHandler { this.result = this.successAction.apply(value); } } - else if (lockFailAction != null) { + if (lockFailAction != null) { + this.result = lockFailAction.get(); + } + int fib = 3; + while (this.result == null && lockFailAction != null && !exResolved && retryCount-- != 0) { + // 使用斐波那契数列进行睡眠时间的增长 + ThreadUtil.safeSleep(calculateFibonacci(fib++) * 10); this.result = lockFailAction.get(); } return this.result; @@ -103,4 +118,16 @@ public final class DistributedLock implements Action, StateHandler { throw (E) t; } + /** + * 计算斐波那契值 + * @param fib + * @return + */ + public int calculateFibonacci(int fib) { + if (fib <= 0 || fib == 1 || fib == 2) { + return 1; + } + return calculateFibonacci(fib - 1) + calculateFibonacci(fib - 2); + } + } diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/StateHandler.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/StateHandler.java index 5654af6396a96a6c70603f63ff375d786540d2a0..406e80087dbac6714803427523763bb62a4350eb 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/StateHandler.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/StateHandler.java @@ -32,6 +32,12 @@ public interface StateHandler { */ StateHandler onException(ExceptionHandler action); + /** + * 控制锁竞争失败时的重试次数 + * @param retryCount + */ + StateHandler retryCount(int retryCount); + /** * 终态,获取锁 * @return result diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java index 60699a6c512054bf7eed4530e487f2203dda22b7..3c995c1782970baef5ef6542ab63a40b264284f5 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java @@ -33,6 +33,11 @@ public class CachedOps extends AbstractCacheOps { */ private final Consumer cachePut; + /** + * 在Redis中锁竞争失败时的重试次数 + */ + private final int retryCount; + /** * 基本构造函数 * @param joinPoint 织入方法 @@ -40,14 +45,16 @@ public class CachedOps extends AbstractCacheOps { * @param cacheQuery 查询缓存函数 * @param cachePut 更新缓存函数 * @param returnType 返回数据类型 + * @param retryCount 锁竞争失败时的重试次数 */ public CachedOps(ProceedingJoinPoint joinPoint, String lockKey, Supplier cacheQuery, - Consumer cachePut, Type returnType) { + Consumer cachePut, Type returnType, int retryCount) { super(joinPoint); this.lockKey = lockKey; this.cacheQuery = cacheQuery; this.cachePut = cachePut; this.returnType = returnType; + this.retryCount = retryCount; } public Supplier cacheQuery() { @@ -66,4 +73,8 @@ public class CachedOps extends AbstractCacheOps { return lockKey; } + public int retryCount() { + return retryCount; + } + }