子类继承父类后,获取ThreadLocal中存储的String为null,原因何在?
问题原因
你的代码返回null的核心问题是执行顺序不匹配:
- TestClass中的
String str = getString();是成员变量初始化代码,会在TestClass对象创建时立即执行,此时TestNG的@BeforeSuite方法还未运行,ThreadLocal里还没存入值,所以返回null。 - 另外,
@BeforeSuite是在整个测试套件启动时执行,若测试方法的执行线程和@BeforeSuite的执行线程不一致(部分TestNG运行场景下会出现),ThreadLocal的线程绑定特性也会导致测试线程拿不到之前存入的值。
解决方法
方法1:在测试方法内直接获取值(最简单)
把getString()的调用移到@Test方法内部,确保在@BeforeSuite执行之后再获取值:
package tests; import base.BaseClass; import org.testng.Assert; import org.testng.annotations.Test; public class TestClass extends BaseClass { @Test public void TestString() { // 此时@BeforeSuite已执行,ThreadLocal已有值 String str = getString(); Assert.assertEquals(str,"I am a String." ); } }
方法2:调整初始化时机,配合TestNG前置注解
如果需要把值存在成员变量中,可以用@BeforeClass(在当前测试类实例化后、测试方法执行前执行)替代@BeforeSuite,并在对应的前置方法中初始化成员变量:
修改BaseClass
package base; import org.testng.annotations.BeforeClass; import org.testng.annotations.AfterSuite; public class BaseClass { private static final ThreadLocal<String> str = new ThreadLocal<>(); public void setString(String string){ str.set(string); } public static String getString(){ return str.get(); } @BeforeClass public void setDesiredString(){ String desiredString = "I am a String."; setString(desiredString); } @AfterSuite public void clearThreadLocal(){ str.remove(); // 用完清理ThreadLocal,避免内存泄漏 } }
修改TestClass
package tests; import base.BaseClass; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class TestClass extends BaseClass { String str; @BeforeClass public void initStr(){ // 在@BeforeClass之后获取值,此时ThreadLocal已有内容 str = getString(); } @Test public void TestString() { Assert.assertEquals(str,"I am a String." ); } }
额外注意点
- ThreadLocal是线程绑定的,必须保证存值和取值在同一个线程执行,否则会拿不到值。
- 使用ThreadLocal后记得在合适的时机调用
remove()(比如@AfterSuite),避免因线程复用导致的内存泄漏。
内容的提问来源于stack exchange,提问作者Aliul Islam Abir
相关产品推荐
相关产品推荐

