You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 20:27:29