使用ReentrantLock替代CountDownLatch为何无法实现同等效果?
为什么你的ReentrantLock重写代码达不到CountDownLatch的效果?
哈哈,我一眼就看出问题所在啦!你这段ReentrantLock的代码完全没利用Condition的等待/唤醒机制,主线程根本没进入阻塞等待状态,自然不会等子线程执行完毕就直接往下跑了。咱们一步步拆解:
先回顾原CountDownLatch的核心逻辑
原代码里,主线程调用countDownLatch.await()后会立刻进入阻塞状态,一直等到子线程执行countDownLatch.countDown()把计数器从1减到0,主线程才会被唤醒,继续执行后面的打印逻辑。这是CountDownLatch专门为“等待一组线程完成”场景设计的机制。
你的ReentrantLock代码的问题点
- 主线程没有阻塞逻辑:你写的主线程只是调用了
lock()然后立刻unlock(),这两步几乎是瞬间完成的,没有任何让主线程停下来等待的代码,所以直接就执行到log.info("ReentrantLock: out thread..")了,完全不会等子线程。 - Condition对象形同虚设:你虽然创建了
Condition condition = lock.newCondition();,但从头到尾既没让主线程调用condition.await()(进入等待状态),也没让子线程调用condition.signal()/signalAll()(唤醒等待的主线程),这个Condition根本没发挥任何作用。
正确的ReentrantLock+Condition写法
要实现和原CountDownLatch一样的效果,你需要利用Condition的await()和signal()来手动实现等待-唤醒逻辑,代码应该是这样的:
public static void myReentrantLockFixed() { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); Thread t = new Thread(() -> { try { log.info("ReentrantLock: in thread.."); Thread.sleep(3000); // 子线程执行完任务后,获取锁并唤醒主线程 lock.lock(); try { condition.signal(); } finally { lock.unlock(); } } catch (InterruptedException e) { e.printStackTrace(); } }); lock.lock(); try { t.start(); // 主线程进入等待,释放锁,直到被子线程唤醒 condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } log.info("ReentrantLock: out thread.."); }
修正后的逻辑说明:
- 主线程先获取锁,调用
condition.await():这会让主线程进入阻塞状态,同时自动释放锁,避免子线程无法获取锁。 - 子线程执行完任务后,先获取锁,调用
condition.signal()唤醒主线程,然后释放锁。 - 主线程被唤醒后,会重新获取锁,然后继续执行后续代码,最后释放锁。
这样就能实现和原CountDownLatch代码完全一致的效果啦!
内容的提问来源于stack exchange,提问作者nimo23
相关产品推荐
相关产品推荐

