CountDownLatch await()未等待最后线程执行结束问题排查
问题根源
你对CountDownLatch的核心等待/通知机制理解没有偏差,输出不符合预期的核心原因是**countDown()的调用时机错误**:
- 你的代码中,工作线程执行完
Thread.sleep(5000)后,会先调用doneSignal.countDown(),再打印"Task ended by thread"日志 - CountDownLatch的规则是:当内部计数减到0的瞬间,所有阻塞在
await()方法的线程会立刻被唤醒执行,不会等待调用countDown()的线程执行完后续代码 - 当第5个线程执行完
countDown()时,doneSignal计数归0,主线程立刻从await()处返回,打印"All Tasks Completed";此时剩下几个还没来得及执行"Task ended"打印的工作线程会和主线程并行输出,就出现了完成提示早于部分任务结束日志的现象。
修复方法
调整performTask()方法内的执行顺序,确保线程所有自身任务逻辑(包括结束日志打印)全部执行完成后,再调用countDown()递减计数即可:
private void performTask() { try { System.out.println("Task started by thread : " + id); Thread.sleep(5000); // 先执行完所有任务收尾逻辑,再通知计数减一 System.out.println("Task ended by thread : " + id); doneSignal.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } }
额外优化建议
当前写法如果任务执行过程中抛出未捕获异常,会导致countDown()无法被调用,最终主线程会永久阻塞在doneSignal.await()处。更稳妥的写法是将countDown()放到finally块中保证一定执行,示例:
@Override public void run() { try { startSignal.await(); performTask(); } catch (InterruptedException e) { e.printStackTrace(); } finally { doneSignal.countDown(); } } private void performTask() throws InterruptedException { System.out.println("Task started by thread : " + id); Thread.sleep(5000); System.out.println("Task ended by thread : " + id); }
调整后运行输出就会和你的预期完全一致。
内容的提问来源于stack exchange,提问作者kaddy
相关产品推荐
相关产品推荐

