do-while循环适合分布式锁重试机制,先执行加锁再判断结果与重试余量;设置maxRetries和attempt计数器,加锁成功则退出,失败则休眠、递增attempt并检查是否继续重试。

在分布式系统中,获取锁通常需要重试机制,而 do-while 循环天然适合“先执行、再判断”的场景——比如先尝试加锁,失败后再检查是否还能重试。结合最大重试次数限制,do-while 能让逻辑更清晰、边界更明确。
核心思路:先试锁,再判结果与重试余量
不同于 while(先判断后执行),do-while 保证至少执行一次加锁操作,避免因初始条件误判跳过首次尝试。关键在于把「是否继续重试」的判断放在循环末尾,同时维护一个递减的重试计数器。
- 定义最大重试次数(如
maxRetries = 3)和当前已尝试次数(attempt = 0) - 循环体中调用分布式锁客户端(如 Redisson、Lettuce 或自研 Redis SETNX 封装)
- 若加锁成功,直接跳出循环或返回 true
- 若失败,休眠一段随机/固定时间(防雪崩),然后
attempt++,再判断attempt
典型代码结构(以 Redis SETNX 为例)
假设使用 Jedis 操作 Redis,锁 key 为 "lock:order:123",过期时间为 30 秒:
String lockKey = "lock:order:123";
String requestId = UUID.randomUUID().toString();
long expireTime = 30L;
int maxRetries = 3;
int attempt = 0;
boolean locked = false;
<p>do {
// 尝试加锁:SET key value EX seconds NX
String result = jedis.set(lockKey, requestId,
new SetParams().ex(expireTime).nx());
if ("OK".equals(result)) {
locked = true;
break;
}</p><pre class="brush:php;toolbar:false;">// 加锁失败,等待后重试(例如指数退避或固定 100ms)
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
attempt++;} while (attempt
if (!locked) { throw new RuntimeException("Failed to acquire distributed lock after " + maxRetries + " attempts"); } // 后续业务逻辑...
注意事项:避免常见陷阱
do-while 本身不解决分布式锁的原子性、可重入、自动续期等问题,它只是控制重试流程。实际使用中需额外保障:
- 锁释放必须校验 requestID:防止误删他人锁(DEL 需用 Lua 脚本保证原子性)
- 超时时间要合理设置:太短易误释放,太长故障恢复慢;建议结合业务最长执行时间 + 缓冲
-
休眠策略建议加入抖动:如
Thread.sleep(50 + (long)(Math.random() * 100)),减少重试冲突 -
不要忽略中断响应:在
sleep前检查Thread.interrupted(),及时退出
进阶建议:封装成可复用工具方法
将上述逻辑抽离为静态工具方法,支持传入锁操作函数、重试策略、超时参数等,提升复用性与可测性:
public static boolean tryLockWithRetry(
Supplier<boolean> lockSupplier,
int maxRetries,
long baseDelayMs) {
int attempt = 0;
do {
if (lockSupplier.get()) {
return true;
}
if (attempt jedis.set("key", "val", params) != null,
3, 100);
</boolean>Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











