在 Java 中实现 "Selenium driver pool" 的正确方法是什么?

What is the right way to implement a "Selenium driver pool" in Java?

我在 Java 中使用 Selenium WebDriver 和 geckodriver 编写了一个 Web 自动化工具。 目前每次执行任务时,都会实例化一个新的 FirefoxDriver 对象。

现在我想实现多线程。我想到的第一种方法是构建类似固定大小池的东西——在启动时实例化 X 个 FirefoxDriver 对象,将它们包装在一个带有 "inUse" 标志的对象中,并使用单例来管理这些实例。

但这是正确的解决方案吗?这是我的第一个 Selenium 项目,整个概念对我来说都是全新的。 经过几天的谷歌搜索和阅读文档后,我自己无法找到该问题的答案。非常感谢您的帮助!

像这样创建一个池是完全合理的。与其编写自己的池,我建议使用现有的通用池,例如经典的 Commons Pool or the more modern spf4j 池。

要使池工作,您的代码必须在使用后可靠地return将驱动程序连接到池中,否则您将泄漏驱动程序(并因此泄漏整个浏览器实例!)。

因此,我会考虑一种不同的方法:为每个线程专用一个驱动程序。您可以使用 ThreadLocal:

private ThreadLocal<WebDriver> drivers = new ThreadLocal<WebDriver>() {
    @Override
    protected WebDriver initialValue() {
        return new FirefoxDriver(); // or whatever
    }

    @Override
    public void remove() {
        WebDriver driver = get();
        if (driver != null) driver.close();
        super.remove();
    }

    @Override
    public void set(WebDriver value) {
        throw new UnsupportedOperationException();
    }
};

仍然有可能泄漏驱动程序,但前提是线程在没有从 ThreadLocal 中删除它们的值的情况下死亡。如果你有一个固定的线程池可以重用,你会没事的。

这种方法的一个缺点是,您最终会为曾经使用过驱动程序的每个线程分配一个驱动程序,即使并非所有这些线程都同时使用驱动程序。如果您有一个专用于使用驱动程序的线程池,并且很少做其他事情,那么这将不是一个严重的问题。但是,如果您有一个执行许多不同类型工作的线程池,则可能是这样。