ExecutorService.execute()静默退出run()方法

时间:2018-12-11 11:14:49

标签: java multithreading junit executorservice

尝试测试我的一个类可以处理在多个线程上的访问。我有一个JUnit测试,在其中创建了一个实现Runnable并运行我的类的类。

当我运行execute时,它在run()方法中到达一行,并且仅在该线程上退出而不报告任何问题,我已经用Try-Catch(Throwable)对其进行了包装,但仍然没有任何迹象错误的。

这是我的代码:

class ConcurrencyTests {
    class ConcurrentComponentTracker implements Runnable {
        private String component;

        ConcurrentComponentTracker(String component) {
            this.component = component;
       }

       @Override
       public void run() {
           try {
           System.out.printf("Component to track: [%s]\n", component);
           ParserHandler parserHandler = new ParserHandler();
           System.out.println(parserHandler.componentTracker(component));
           }
           catch (Throwable t) {
               t.printStackTrace();
           }
       }
   }

    @Test
    void runRunner() {
        ExecutorService executor = Executors.newFixedThreadPool(4);
        String[] componentsToTrack = {"x", "y", "z"};

        executor.execute(new ConcurrentComponentTracker(componentsToTrack[0]));
        executor.execute(new ConcurrentComponentTracker(componentsToTrack[1]));
        executor.execute(new ConcurrentComponentTracker(componentsToTrack[2]));
    }
}

输出:

Component to track: [x]

Component to track: [y]

Component to track: [z]

似乎只是在ParserHandler实例化行上退出而不报告任何内容。当尝试调试并进入该行时,它只是跳到最后而没有让我检查ParserHandler类的实例。

2 个答案:

答案 0 :(得分:2)

Whomever在评论中回答,然后删除它为我解决了问题。我的主要JUnit线程没有等待其他线程完成。因此,我将这些行添加到最后,并按预期工作:

executor.shutdown();

try {
    executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException e) {
    e.printStackTrace();
}

答案 1 :(得分:0)

JUnit测试应该实际测试和验证结果。在这种特殊情况下,您的测试产生的输出应由开发人员/测试人员验证,因此这不是自动化的。 建议您使用Future<?>来跟踪任务执行状态。对于Runnable的任务,如果任务成功执行,则get()的{​​{1}}方法将返回Future<?>,否则将转发给您null包裹的异常。代码将如下所示:

ExecutionException

在执行此操作之前,应删除@Test void runRunner() { ExecutorService executor = Executors.newFixedThreadPool(3); String[] componentsToTrack = {"x", "y", "z"}; assertNull(executor.submit(new ConcurrentComponentTracker(componentsToTrack[0]).get()); assertNull(executor.submit(new ConcurrentComponentTracker(componentsToTrack[1]).get()); assertNull(executor.submit(new ConcurrentComponentTracker(componentsToTrack[2]).get()); // cleanup and shutdown pool executor.shutdown(); try { executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { // ignore this } } 方法内的try/catch块。

您可能需要改进的另一件事是使executor成为测试类的一个字段,并使用run()@BeforeClass,...通过传统的JUnit生命周期对其进行管理,以进行初始化,测试之间的清理,关闭优雅地游泳池。请记住,从资源的角度来看,线程池并不是那么便宜。

希望有帮助!

PS ,如果您的目标是对@Before进行并行处理,则可以将ConcurrentComponentTracker存储在某些集合中,并在提交所有任务后运行断言。