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

如何确保在java并行处理中一个代码块只由一个线程执行,java,multithreading,parallel-processing,Java,Multithreading,Parallel Processing,我有一个使用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 = R

我有一个使用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分钟多一点。我希望引入并行性,这样每个带有3行Results对象、断言和生成或报告的代码块(带有特定标记)都由单个线程并行运行。因此,从理论上讲,整个处理时间将略多于5分钟。这意味着带有DTC的块在一个线程上运行,WNG块在不同的线程上运行,FFD块在不同的线程上运行。在每个块中,只有一条螺纹是可以的

我尝试使用Executor服务,下面是代码

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();
}

使它再次成为一个顺序程序。
我希望线程1被分配给标记@e2eDTC,并仅使用该标记运行测试,方式与线程2到@e2eWNG和线程3到@e2eFFD相同。有可能有这样的设置吗?我不是一个java开发人员,因此我寻求一些关于如何实现这一点的建议。这里也没有main()方法

哈希集不是线程安全的。您可以使用创建同步集

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

您的解决方案非常有用,性能非常好。然而,有时我确实会遇到一些随机故障。这是意料之中的吗?@Pakira非常感谢你。这看起来非常干净,非常像您的解决方案。我面临的问题是,它有调用它的主要方法。由于我正在使用maven test命令来运行此文件,因此include main method会给我以下错误
Tests in error:initializationError(eCare.ThreadTest):method main()不应该是静态initializationError(eCare.ThreadTest):Method main应该没有参数
如果我将main重命名为另一个方法名,如
public void testParallel()抛出InterruptedException{
它根本不执行测试。看起来像是一个我现在可能缺少的琐碎问题@pakirathanking@Pakira。它看起来不像是重写和执行run()方法。我打印了调试结果,但似乎根本没有进入run()方法执行。有什么想法吗?我也在寻找更多信息。将start()更改为run(),似乎可以工作。有一些问题,但它似乎对我有效。请阅读以下内容:出于各种原因,start()不工作,但run()可以工作是的。我会深入挖掘并将我的发现留在这里。谢谢你的帮助@Pakira
ExecutorService executorService = Executors.newSingleThreadExecutor()

  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());
     }
    }

     }