ExecutorService.execute() 静默退出 运行() 方法
ExecutorService.execute() silently exits run() method
尝试测试我的 classes 之一是否可以处理在多个线程上的访问。我有一个 JUnit 测试,我在其中创建了一个 class 来实现 Runnable
和 运行 我的 class.
当我 运行 执行时,它到达 运行() 方法中的一行并在该线程上退出而不报告任何问题,我用 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 class 实例化。
谁在评论中回答然后删除它就解决了我的问题。我的主 JUnit 线程没有等待其他线程完成。所以我将这些行添加到最后,它按预期工作:
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException e) {
e.printStackTrace();
}
JUnit 测试应该实际测试和验证结果。在这种特殊情况下,您的测试产生的输出应该由 developer/tester 验证,因此这不是自动化。
我建议您使用 Future<?>
来跟踪任务执行的状态。对于 Runnable
任务 get()
如果任务执行成功,Future<?>
方法将 return 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
块。
您可能可以改进的另一件事是使执行程序成为测试的一个字段 class 并使用传统的 JUnit 生命周期管理它,使用 @BeforeClass
、@Before
、... 来初始化,在测试之间清理,优雅地关闭池。请记住,从资源的角度来看,线程池并不便宜。
希望对您有所帮助!
P.S. 如果你的目标是并行处理你的 ConcurrentComponentTracker
你可以将 Future<?>
存储在一些集合中并且 运行 提交所有任务后的断言。
尝试测试我的 classes 之一是否可以处理在多个线程上的访问。我有一个 JUnit 测试,我在其中创建了一个 class 来实现 Runnable
和 运行 我的 class.
当我 运行 执行时,它到达 运行() 方法中的一行并在该线程上退出而不报告任何问题,我用 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 class 实例化。
谁在评论中回答然后删除它就解决了我的问题。我的主 JUnit 线程没有等待其他线程完成。所以我将这些行添加到最后,它按预期工作:
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException e) {
e.printStackTrace();
}
JUnit 测试应该实际测试和验证结果。在这种特殊情况下,您的测试产生的输出应该由 developer/tester 验证,因此这不是自动化。
我建议您使用 Future<?>
来跟踪任务执行的状态。对于 Runnable
任务 get()
如果任务执行成功,Future<?>
方法将 return 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
块。
您可能可以改进的另一件事是使执行程序成为测试的一个字段 class 并使用传统的 JUnit 生命周期管理它,使用 @BeforeClass
、@Before
、... 来初始化,在测试之间清理,优雅地关闭池。请记住,从资源的角度来看,线程池并不便宜。
希望对您有所帮助!
P.S. 如果你的目标是并行处理你的 ConcurrentComponentTracker
你可以将 Future<?>
存储在一些集合中并且 运行 提交所有任务后的断言。