getClass()。getName()返回null

时间:2014-12-30 13:21:45

标签: java multithreading thread-safety testng

我正在使用testNG为我们的测试编写者提供一个“框架”来加速测试的开发。为了实现这一点,我有一个抽象的Test类。所有书面测试都来自此Test类。这些测试可以由testNG并行运行。现在我注意到有时在@BeforeClass方法中,我的简单'getClass()。getName()'方法在并行执行时返回null。

private static ThreadLocal<String> className;

@BeforeClass
public void init(){
        initName();
        className.set(getClass().getName());            
        log("Starting test " + className.get());
}

private synchronized void initName(){
    if(className == null){
        className = new ThreadLocal<>();
    }
}

当我为一系列并行测试运行时,我得到了这个输出:

...
Starting test com.mycompany.testsets.LocalTestSet$IntegrationTest3
Starting test null
Starting test com.mycompany.testsets.LocalTestSet$IntegrationTest1
...

一些评论:
Threadlocal ClassName必须是静态的(我稍后会在@Dataprovider中使用它的值)
由于它随机出现并且可能发生在任何测试中,我认为这是一个线程安全问题,但我不知道如何使'getClass()。getName()'更加线程安全。

感谢您的帮助

2 个答案:

答案 0 :(得分:2)

你似乎有竞争条件。如果一个线程在另一个线程调用initName之前调用log,则新的ThreadLocal将没有值,即。将返回null

此处没有线程安全保护null内的initName检查。

答案 1 :(得分:0)

跳过initName中的延迟初始化!它不是线程安全的。

相反,直接初始化ThreadLocal字段(并注意final):

private static final ThreadLocal<String> className = new ThreadLocal<>();

(顺便说一句:为什么你需要一个ThreadLocal来保存当前班级的名字?只需拨打getClass().getName()),你就可以轻松获得它。