Answer
ThreadLocal WebDriver in Selenium
When tests run in parallel, multiple threads share the same class instance. Without ThreadLocal, threads overwrite each other''s driver variable — causing NullPointerException, cross-thread interference, and flaky tests.
Problem Without ThreadLocal
Java
// BROKEN — shared static driver in parallel
public class BaseTest {
protected static WebDriver driver; // DANGER: shared across threads
@BeforeMethod
public void setUp() {
driver = new ChromeDriver(); // Thread 2 overwrites Thread 1's driver!
}
}
Solution — ThreadLocal<WebDriver>
Java
public class DriverManager {
private static final ThreadLocal<WebDriver> tlDriver = new ThreadLocal<>();
public static void setDriver(WebDriver driver) {
tlDriver.set(driver);
}
public static WebDriver getDriver() {
return tlDriver.get();
}
public static void removeDriver() {
if (tlDriver.get() != null) {
tlDriver.get().quit();
tlDriver.remove(); // CRITICAL — prevents memory leak
}
}
}
BaseTest with ThreadLocal
Java
public class BaseTest {
@BeforeMethod
public void setUp() {
WebDriverManager.chromedriver().setup();
DriverManager.setDriver(new ChromeDriver());
DriverManager.getDriver().manage().window().maximize();
}
@AfterMethod(alwaysRun = true)
public void tearDown() {
DriverManager.removeDriver(); // quits + removes from ThreadLocal
}
}
BasePage with ThreadLocal Driver
Java
public class BasePage {
protected WebDriver driver;
protected WebDriverWait wait;
public BasePage() {
this.driver = DriverManager.getDriver(); // gets THIS thread's driver
this.wait = new WebDriverWait(driver, Duration.ofSeconds(15));
}
}
testng.xml for Parallel Methods
XML
<suite name="ParallelSuite" parallel="methods" thread-count="4">
<test name="RegressionTests">
<classes>
<class name="tests.LoginTest"/>
<class name="tests.CheckoutTest"/>
</classes>
</test>
</suite>
How ThreadLocal Works
| Thread | tlDriver value |
|---|---|
| Thread-1 | ChromeDriver instance A |
| Thread-2 | ChromeDriver instance B |
| Thread-3 | ChromeDriver instance C |
Each thread sees only its own driver. getDriver() returns the correct instance for the calling thread automatically.
Critical Rules
- ✓Always call
tlDriver.remove()in@AfterMethod— otherwise driver objects leak in thread pools - ✓Never pass driver as a parameter between page classes — use
DriverManager.getDriver()everywhere - ✓
ThreadLocalonly works for same-JVM parallelism — for Grid, each node has its own JVM
