如何确保在 java 中的并行处理中,代码块仅由一个线程执行



我有一个使用 maven 命令行运行的测试类,如下所示:

public class TestRunner {
@org.junit.Test
public void testParallel() throws InterruptedException, ExecutionException {

//Takes 5 mins. Has 20 different tests with the tag @e2eDTC
Results DTC = Runner.path("classpath:").tags("@e2eDTC").reportDir("target/cucumber-html- 
reports").parallel(1);
assertTrue(DTC.getErrorMessages(), DTC.getFailCount() == 0); 
generateReport(DTC.getReportDir());
// Takes 4 min. Has 25 different tests the tag @e2eWNG
Results WNG = Runner.path("classpath:").tags("@e2eWNG").reportDir("target/cucumber-html- 
reports").parallel(1);
assertTrue(WNG.getErrorMessages(), WNG.getFailCount() == 0); 
generateReport(WNG.getReportDir());
// Takes 3 min. Has 18 different tests with the tag @e2eFFD
Results FFD = Runner.path("classpath:").tags("@e2eFFD").reportDir("target/cucumber-html- 
reports").parallel(1);
assertTrue(FFD.getErrorMessages(), FFD.getFailCount() == 0); 
generateReport(FFD.getReportDir());
}
}

上面的代码显然是连续的,需要 12 分钟多一点。我希望引入并行性,以便每个代码块(带有特定标签(与 Results 对象、断言和生成或报告的 3 行并行运行。因此,理论上整体处理时间将略高于 5 分钟。这意味着具有DTC的块在线程上运行,WNG块在不同的线程上运行,FFD块在单独的线程上运行。在每个块中,只有一个线程是可以的。

我尝试使用执行人服务,这是代码

public class TestRunner {
@org.junit.Test
public void testParallel() throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {
public String call() throws Exception {
Results DTC = Runner.path("classpath:").tags("@e2eDTC").reportDir("target/cucumber-html-reports").parallel(1);
assertTrue(DTC.getErrorMessages(), DTC.getFailCount() == 0); 
generateReport(DTC.getReportDir());
return "DTC Success";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
Results WNG = Runner.path("classpath:").tags("@e2eWarnings").reportDir("target/cucumber-html-reports").parallel(1);
assertTrue(WNG.getErrorMessages(), WNG.getFailCount() == 0); 
generateReport(WNG.getReportDir());
return "WNG Success";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
Results FFD = Runner.path("classpath:").tags("@e2eFFD").reportDir("target/cucumber-html-reports").parallel(1);
assertTrue(FFD.getErrorMessages(), FFD.getFailCount() == 0); 
generateReport(FFD.getReportDir());
return "FFD Success";
}
});
List<Future<String>> futures = executorService.invokeAll(callables);
for(Future<String> future : futures){
System.out.println("future.get = " + future.get());
}
executorService.shutdown();
}

但是,这给了我们 3 个线程,它会将线程随机分配给每个块中的多个测试并导致错误。

改变

ExecutorService executorService = Executors.newFixedThreadPool(3);

ExecutorService executorService = Executors.newSingleThreadExecutor()

再次使其成为顺序程序。 我希望将线程 1 分配给标签@e2eDTC并仅使用该标签运行测试,并以相同的方式将线程 2 分配给@e2eWNG,线程 3 到 @e2eFFD。有没有可能有这样的设置?我不是Java开发人员,因此寻求有关如何实现这一目标的建议。这里也没有main((方法。

HashSet 不是线程安全的。您可以创建一个同步集

Set<Callable<String>> callables = Collections.synchronizedSet(new HashSet<Callable<String>>());

或者你可以使用数组列表

List<Callable<String>> tasksList = new ArrayList<Callable<String>>();

我不认为您需要执行器池服务,因为您将无法控制,因为线程是由操作系统分配的。您可以使用以下代码

public class ThreadTest {
@org.junit.Test
public void testFunc() {
ThreadTest test = new ThreadTest();
Thread a = new Thread(test.new DTC());
Thread b = new Thread(test.new WNG());
Thread c = new Thread(test.new FFD());
a.start();
b.start();
c.start();
}

class DTC implements Runnable {
@Override
public void run() {
try {
// Your logic
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("DTC Success " + Thread.currentThread().getName());
}
}
class WNG implements Runnable {
@Override
public void run() {
try {
// Your logic
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("WNG Success "+ Thread.currentThread().getName());
}
}
class FFD implements Runnable {
@Override
public void run() {
try {
// Your logic
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("FFD Success "+ Thread.currentThread().getName());
}
}
}

最新更新