如何等待其他线程获取锁?不使用Thread.sleep的并发问题解决方案
解决锁获取后的并发等待问题(无需Thread.sleep)
兄弟,这个轮询Thread.sleep()的坑我之前踩过好几次——既浪费CPU资源,还容易因为sleep时长设置不合理导致逻辑延迟或者误判。给你几个优雅的解决方案,完全不用依赖轮询:
方案1:用CountDownLatch实现精准等待
这是最直接的方案,专门用来解决“等待某个/某些操作完成后再继续”的场景:
// 初始化一个计数为1的CountDownLatch,代表我们要等1个事件完成 CountDownLatch latch = new CountDownLatch(1); acquireLockAndRunOnNewThread(() -> { acquiredLock = true; latch.countDown(); // 锁获取完成后,触发计数减1 continueWithOtherStuff(); }); // 主线程会阻塞在这里,直到latch的计数变为0(也就是锁获取完成) latch.await(); // 现在可以安全执行后续逻辑了 continueWithOtherStuffThatAlsoAcquiresALockAtSomePointInTime();
为什么好用?await()会让主线程进入高效的阻塞状态,不会像sleep那样空耗CPU;而且只要锁获取完成就会立即唤醒主线程,没有时间精度问题。
方案2:用CompletableFuture简化异步流程(Java 8+)
如果你的项目用Java 8及以上,CompletableFuture能让异步代码更简洁,还自带异常处理能力:
// 将锁获取逻辑包装成异步任务 CompletableFuture<Void> lockTask = CompletableFuture.runAsync(() -> { acquiredLock = true; continueWithOtherStuff(); }); // 等待异步任务完成(锁获取完成),主线程会阻塞直到任务结束 lockTask.join(); // 执行后续需要锁的逻辑 continueWithOtherStuffThatAlsoAcquiresALockAtSomePointInTime();
额外优势:
如果后续需要处理锁获取失败的异常,可以直接用exceptionally()或者handle()方法,比手动处理线程异常方便得多。
方案3:用Object.wait()/notify()实现原生通知机制
如果你不想引入额外工具类,Java原生的等待/通知机制也能解决问题,但要注意同步块的使用:
final Object waitLock = new Object(); boolean acquiredLock = false; acquireLockAndRunOnNewThread(() -> { synchronized(waitLock) { acquiredLock = true; waitLock.notify(); // 通知主线程:锁已经拿到了 } continueWithOtherStuff(); }); synchronized(waitLock) { // 用while循环防止虚假唤醒,确保确实是锁获取完成才继续 while (!acquiredLock) { waitLock.wait(); // 主线程进入等待,直到被notify唤醒 } } continueWithOtherStuffThatAlsoAcquiresALockAtSomePointInTime();
注意事项:wait()和notify()必须在同步块内调用,而且一定要用while循环检查条件(不能用if),避免因为JVM的虚假唤醒导致逻辑出错。
内容的提问来源于stack exchange,提问作者Ari
相关产品推荐
相关产品推荐

