Java 重用工作实例以处理多个任务

Java 重用工作实例以处理多个任务,java,concurrency,java.util.concurrent,Java,Concurrency,Java.util.concurrent,我有一个基于Selenium的web测试应用程序,但这在这里并不重要,因为它连续执行了大量测试用例。它需要几个小时才能完成,测试用例的数量也在增加,所以我想使用多个web浏览器实例来并行执行多个测试用例。测试用例之间没有依赖关系 非常简单,它看起来像这样: TestExecutor executor = new TestExecutor(new FirefoxDriver()); for (TestCase test: tests) { executor.execute(test);

我有一个基于Selenium的web测试应用程序,但这在这里并不重要,因为它连续执行了大量测试用例。它需要几个小时才能完成,测试用例的数量也在增加,所以我想使用多个web浏览器实例来并行执行多个测试用例。测试用例之间没有依赖关系

非常简单,它看起来像这样:

TestExecutor executor = new TestExecutor(new FirefoxDriver());
for (TestCase test: tests) {
    executor.execute(test);
    // use results here
}
现在我不知道该如何将其并行化。我可以轻松创建几个连接到多个web浏览器的TestExecutor作为可调用项,并使用Executors、CompletionServices和其他优秀的帮助器类,但我如何:

一旦新的测试用例与以前的测试用例一起准备好,就将其传递给TestExecutor?Callable中的call方法不带任何参数,因此我可能必须在TestExecutor类中实现一些setNextSetCase来实现这一点,我觉得这不是很好。还有更好的选择吗

是否重用TestExecutor实例来执行下一个测试用例?由于每个TestExecutor实例都需要一个web浏览器实例,因此初始化它需要很长时间,如果我要为每个测试用例创建一个新的TestExecutor,则会导致许多窗口在屏幕上闪烁


我建议设置一个测试人员队列/列表。然后创建一个可调用/可运行的包住测试用例。ExecutorService的线程数将与TestExecutor列表中的线程数相同。可运行的第一步是从队列中检索/弹出TestExecutor。它将利用执行器进行测试,然后在完成后将其放回队列。

我建议设置一个测试执行器队列/列表。然后创建一个可调用/可运行的包住测试用例。ExecutorService的线程数将与TestExecutor列表中的线程数相同。可运行的第一步是从队列中检索/弹出TestExecutor。它将利用执行器进行测试,然后在完成后将其放回队列中

一旦新的测试用例与以前的测试用例一起准备好,就将其传递给TestExecutor

如果我理解你,这是一个常见的问题。线程池中有许多线程,但每个线程都有一些上下文—在本例中是一个web浏览器。您不希望必须为提交到线程池的每个作业启动新浏览器

BlockingQueue<TestCase> testCaseQueue = new LinkedBlockingQueue<>();
for (TestCase test: tests) {
    testCaseQueue.add(test);
}
// now make your executors and run them in a thread-pool
TestExecutor testExecutor =
     new TestExecutor(new FirefoxDriver(), testCaseQueue);
ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.submit(testExecutor);
...
// once you've submitted your last executor, you shutdown the pool
threadPool.shutdown();

...
// inside of the executor, they dequeue tests from `testCaseQueue`
while (!shutdown) {
    TestCase testCase = testCaseQueue.poll(0, TimeUnit.MILLISECONDS);
    if (testCase == null) {
       break;
    }
    ...
} 
下面是一些关于如何实现这一点的想法

拥有TestCase对象的BlockingQueue。然后,每个线程初始化其浏览器,然后从TestCase对象队列中退出队列,直到队列为空或某个关闭布尔值设置为true。您可以将TestExecutor对象提交到一个线程池中,但它们会通过您自己的队列自行退出TestCase对象的队列。您不会将测试用例提交到线程池

BlockingQueue<TestCase> testCaseQueue = new LinkedBlockingQueue<>();
for (TestCase test: tests) {
    testCaseQueue.add(test);
}
// now make your executors and run them in a thread-pool
TestExecutor testExecutor =
     new TestExecutor(new FirefoxDriver(), testCaseQueue);
ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.submit(testExecutor);
...
// once you've submitted your last executor, you shutdown the pool
threadPool.shutdown();

...
// inside of the executor, they dequeue tests from `testCaseQueue`
while (!shutdown) {
    TestCase testCase = testCaseQueue.poll(0, TimeUnit.MILLISECONDS);
    if (testCase == null) {
       break;
    }
    ...
} 
另一个想法是将TestCase提交到线程池,并使用ThreadLocal获取先前为测试配置的浏览器。这并不是最理想的,因为它使得在测试完成后很难适当地终止浏览器

一旦新的测试用例与以前的测试用例一起准备好,就将其传递给TestExecutor

如果我理解你,这是一个常见的问题。线程池中有许多线程,但每个线程都有一些上下文—在本例中是一个web浏览器。您不希望必须为提交到线程池的每个作业启动新浏览器

BlockingQueue<TestCase> testCaseQueue = new LinkedBlockingQueue<>();
for (TestCase test: tests) {
    testCaseQueue.add(test);
}
// now make your executors and run them in a thread-pool
TestExecutor testExecutor =
     new TestExecutor(new FirefoxDriver(), testCaseQueue);
ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.submit(testExecutor);
...
// once you've submitted your last executor, you shutdown the pool
threadPool.shutdown();

...
// inside of the executor, they dequeue tests from `testCaseQueue`
while (!shutdown) {
    TestCase testCase = testCaseQueue.poll(0, TimeUnit.MILLISECONDS);
    if (testCase == null) {
       break;
    }
    ...
} 
下面是一些关于如何实现这一点的想法

拥有TestCase对象的BlockingQueue。然后,每个线程初始化其浏览器,然后从TestCase对象队列中退出队列,直到队列为空或某个关闭布尔值设置为true。您可以将TestExecutor对象提交到一个线程池中,但它们会通过您自己的队列自行退出TestCase对象的队列。您不会将测试用例提交到线程池

BlockingQueue<TestCase> testCaseQueue = new LinkedBlockingQueue<>();
for (TestCase test: tests) {
    testCaseQueue.add(test);
}
// now make your executors and run them in a thread-pool
TestExecutor testExecutor =
     new TestExecutor(new FirefoxDriver(), testCaseQueue);
ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.submit(testExecutor);
...
// once you've submitted your last executor, you shutdown the pool
threadPool.shutdown();

...
// inside of the executor, they dequeue tests from `testCaseQueue`
while (!shutdown) {
    TestCase testCase = testCaseQueue.poll(0, TimeUnit.MILLISECONDS);
    if (testCase == null) {
       break;
    }
    ...
} 
另一个想法是将TestCase提交到线程池,并使用ThreadLocal获取先前为测试配置的浏览器。这并不是最理想的,因为它使得在测试完成后很难适当地终止浏览器


我明白了,谢谢。但我不明白在这种情况下使用Executor服务的意义。我们从中得到了什么?在本例中,没有在运行时提交作为TestExecutor的新任务,因此ExecutorService实际上没有要调度的内容。我可以创建一些TestExecutor,像您建议的那样在c'tor中传递testCaseQueue作为线程实例,然后启动它们中的每一个。对吗?是的,没有必要@Pinni。很多人总是使用ExecutorService,而不是自己实例化线程。我明白了,谢谢。但我不明白在这种情况下使用Executor服务的意义。我们从中得到了什么?在此情况下,测试人员不会在测试期间提交任何新任务
运行时,因此ExecutorService实际上没有要调度的内容。我可以创建一些TestExecutor,像您建议的那样在c'tor中传递testCaseQueue作为线程实例,然后启动它们中的每一个。对吗?是的,没有必要@Pinni。很多人总是使用ExecutorService,而不是自己实例化线程。