在Java中实现“Selenium驱动程序池”的正确方法是什么?

时间:2016-10-07 10:56:31

标签: java multithreading selenium webautomation

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

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

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

1 个答案:

答案 0 :(得分:1)

创建这样的池是完全合理的。我建议使用现有的通用池,例如经典的Commons Pool或更现代的spf4j池,而不是编写自己的池。

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

因此,我会考虑一种不同的方法:将驱动程序专用于每个线程。您可以使用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中删除它们的值时。如果你有一个固定的线程池,你可以重复使用,你会没事的。

这种方法的一个缺点是,对于曾经使用过驱动程序的每个线程,你最终得到一个驱动程序,即使并非每个线程都同时使用驱动程序。如果你有一个致力于使用驱动程序的线程池,并且没有其他功能,那么这将不是一个重大问题。但是如果你有一个线程池来完成许多不同类型的工作,那么可能就是这样。