Java ExecutorService.execute()以静默方式退出run()方法
尝试测试我的一个类是否可以处理在多个线程上被访问的问题。我有一个JUnit测试,其中我创建了一个类来实现Java ExecutorService.execute()以静默方式退出run()方法,java,multithreading,junit,executorservice,Java,Multithreading,Junit,Executorservice,尝试测试我的一个类是否可以处理在多个线程上被访问的问题。我有一个JUnit测试,其中我创建了一个类来实现Runnable并运行我的类 当我运行execute时,它到达run()方法中的一行,并在该线程上退出,而不报告任何问题,我用Try-Catch(Throwable)将其包装起来,但仍然没有出现问题的迹象 这是我的密码: class ConcurrencyTests { class ConcurrentComponentTracker implements Runnable {
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]));
}
}
以及输出:
要跟踪的组件:[x]
要跟踪的组件:[y]
要跟踪的组件:[z]
它似乎只是在ParserHandler实例化行上退出,而没有报告任何内容。当尝试调试并进入该行时,它只跳到最后,而不让我检查ParserHandler类实例化。任何人在评论中回答并删除它,都为我解决了问题。我的主要JUnit线程没有等待其他线程完成。所以我把这些线钉到了最后,它果然起了作用:
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException e) {
e.printStackTrace();
}
JUnit测试实际上应该测试和验证结果。在这种特殊情况下,测试产生的输出应该由开发人员/测试人员验证,因此这不是自动化。 我建议您使用
Future
来跟踪任务执行的状态。对于Runnable
任务get()
Future的方法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
}
}
在执行此操作之前,应删除run()
方法中的try/catch
块
您可能可以改进的另一件事是使executor成为测试类的一个字段,并使用传统的JUnit生命周期管理它,使用@BeforeClass
,@Before
。。。要进行初始化,请在测试之间进行清理,并正常关闭池。请记住,从资源的角度来看,线程池并不便宜
希望有帮助
p.S.如果您的目标是并行处理您的
ConcurrentComponentTracker
,您可以将Future
存储在一些集合中,并在提交所有任务后运行断言。当我无法使用main
方法复制注释时,我删除了注释。这实际上是一个有趣的案例:只有当我用JUnit测试主线程时,它才会终止。将其作为普通java应用程序运行效果很好(我不知道junit会做这样的事情)