TestNG并行方法中Java同步代码失效问题排查
问题分析与解决方案
嘿,这个问题我之前踩过坑!核心原因其实是TestNG并行执行方法时的实例创建策略和你对synchronized锁的理解出现了偏差。
为什么synchronized看起来失效了?
TestNG在parallel="methods"模式下,默认行为是为每个测试方法创建一个独立的测试类实例。也就是说你的testCaseOne和testCaseTwo是在两个完全不同的TestParallelOne对象实例上运行的。
而Java中,实例级别的synchronized方法,锁的是当前对象实例(this)。两个不同的实例持有不同的锁,所以两个线程执行test()时完全不会互相阻塞,自然就达不到你预期的同步效果。
针对你场景的最优解决方案
既然你想保留同步方法的思路,只需要让两个线程共享同一把锁即可,这里有两种最贴合你需求的方案:
方案1:把test()改为静态同步方法
静态同步方法的锁是类对象(TestParallelOne.class),不管TestNG创建多少个实例,所有线程都会竞争这同一把锁。修改后的代码如下:
package com.parallel; import org.testng.annotations.Test; public class TestParallelOne { @Test public void testCaseOne() { System.out.println("Test Case One with Thread Id:- " + Thread.currentThread().getId()); test(); } @Test public void testCaseTwo() { System.out.println("Test Case two with Thread Id:- " + Thread.currentThread().getId()); test(); } // 改为静态同步方法 public static synchronized void test() { for(int i =0; i < 10; i++) System.out.println(i); } }
方案2:使用类级显式锁
如果不想把方法改成静态的,也可以自定义一个静态的锁对象,让所有实例共享:
package com.parallel; import org.testng.annotations.Test; public class TestParallelOne { // 静态锁对象,所有实例共享 private static final Object SHARED_LOCK = new Object(); @Test public void testCaseOne() { System.out.println("Test Case One with Thread Id:- " + Thread.currentThread().getId()); test(); } @Test public void testCaseTwo() { System.out.println("Test Case two with Thread Id:- " + Thread.currentThread().getId()); test(); } public void test() { // 用共享锁同步代码块 synchronized(SHARED_LOCK) { for(int i =0; i < 10; i++) System.out.println(i); } } }
不推荐的方案:强制TestNG使用单例实例
TestNG提供了@Instance注解可以指定测试类为单例,这样所有测试方法都会在同一个实例上执行,实例同步方法的锁就会生效:
import org.testng.annotations.Instance; import org.testng.annotations.Test; @Instance(Instance.SINGLETON) public class TestParallelOne { // 原有代码不变 }
但这种方式会打破TestNG默认的测试隔离性,容易导致测试方法之间的状态污染,除非你能确保测试方法完全无状态,否则不建议使用。
验证效果
修改后重新运行你的suite.xml,你会看到先获取锁的线程会完整执行完test()的循环后,另一个线程才会开始执行,同步效果就符合你的预期了。
内容的提问来源于stack exchange,提问作者std.nullptr
相关产品推荐
相关产品推荐

