多线程、并发与Thread.sleep()未按预期工作问题排查
ReentrantLock测试仅单个线程获取锁的问题排查与解决
问题场景
实现了lockAndWait方法,逻辑是获取ReentrantLock锁后,持有锁休眠1秒再释放。测试时启动10个线程调用该方法,但日志里只看到一个线程成功获取锁;移除Thread.sleep(1000)后,多个线程能正常获取锁。最终通过修改测试代码,用Thread.join等待所有线程执行,问题解决。
原方法代码
private final Lock lock = new ReentrantLock(); public void lockAndWait() { logger.info("I {} am here", Thread.currentThread().getName()); lock.lock(); try { logger.info("I {} got the lock", Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } finally { lock.unlock(); } }
原测试代码(存在问题)
@Test public void lockTest() { for (int i = 0; i < 10; i++) { new Thread(() -> lockAndWait()).start(); } }
问题原因
JUnit的测试方法运行在主线程中,主线程执行完毕后,整个测试进程会直接终止,不会主动等待子线程完成:
- 原测试里,主线程循环启动10个线程后就结束了。第一个线程获取锁后休眠1秒的过程中,主线程已经终止,剩余9个线程还在等待锁或刚启动,根本没机会执行,所以日志只显示第一个线程的锁获取记录。
- 移除
Thread.sleep(1000)后,线程执行速度极快,主线程结束前可能有多个线程完成了加锁、执行、释放的流程,看起来符合预期,但这只是巧合,测试逻辑本身依然存在漏洞。
解决方法:用Thread.join等待所有子线程执行完毕
修改测试代码,保存所有启动的线程实例,遍历调用Thread.join(),让主线程等待每个子线程执行完成后再结束:
@Test public void policyUsageTest() throws InterruptedException { List<Thread> threads = new ArrayList<>(); for (int i = 0; i < 10; i++) { Thread thread = new Thread(() -> lockAndWait()); thread.start(); threads.add(thread); } // 等待所有线程执行完毕 for (Thread thread : threads) { thread.join(); } }
修改后,主线程会一直等待所有10个线程完成加锁、休眠、释放锁的流程后才结束,日志会显示所有线程依次获取锁的记录,符合预期。
内容的提问来源于stack exchange,提问作者deko
相关产品推荐
相关产品推荐

