【发布时间】:2015-06-04 08:02:38
【问题描述】:
我刚开始阅读 JUnit 4.13 (https://github.com/junit-team/junit) 的代码,对 org.junit.internal.runners.statements.FailOnTimeout 的实现有点困惑:
@Override
public void evaluate() throws Throwable {
CallableStatement callable = new CallableStatement();
FutureTask<Throwable> task = new FutureTask<Throwable>(callable);
ThreadGroup threadGroup = new ThreadGroup("FailOnTimeoutGroup");
Thread thread = new Thread(threadGroup, task, "Time-limited test");
thread.setDaemon(true);
thread.start();
callable.awaitStarted();
Throwable throwable = getResult(task, thread);
if (throwable != null) {
throw throwable;
}
}
/**
* Wait for the test task, returning the exception thrown by the test if the
* test failed, an exception indicating a timeout if the test timed out, or
* {@code null} if the test passed.
*/
private Throwable getResult(FutureTask<Throwable> task, Thread thread) {
try {
if (timeout > 0) {
return task.get(timeout, timeUnit); // HERE limits the time
} else {
return task.get();
}
} catch (InterruptedException e) {
return e; // caller will re-throw; no need to call Thread.interrupt()
} catch (ExecutionException e) {
// test failed; have caller re-throw the exception thrown by the test
return e.getCause();
} catch (TimeoutException e) {
return createTimeoutException(thread);
}
}
CallableStatement 在哪里:
private class CallableStatement implements Callable<Throwable> {
private final CountDownLatch startLatch = new CountDownLatch(1);
public Throwable call() throws Exception {
try {
startLatch.countDown();
originalStatement.evaluate(); // HERE the test runs
} catch (Exception e) {
throw e;
} catch (Throwable e) {
return e;
}
return null;
}
public void awaitStarted() throws InterruptedException {
startLatch.await();
}
}
以下是我对代码的理解:
evaluate() 为测试方法启动一个新线程。 callable.awaitStarted() 阻止 evaluate() 直到 startLatch.countDown(),然后 getResult() 乘以测试方法。
这是我的问题:
- 为什么
thread(在evaluate())应该是一个守护线程? -
CountDownLatch是否仅用于阻止getResult()直到thread运行?它真的有效吗(我认为没有什么可以避免callable.awaitStarted()和getResult()之间的上下文切换)?有没有“更简单”的方法来做到这一点?
我对并发不是很熟悉。如果有人能解释这些或指出我的错误,我将不胜感激。谢谢。
关于第二个问题的更多解释:
我将这两个线程分别表示为“evaluate() 线程”和“CallableStatement 线程”。
我认为当callable.awaitStarted() 执行到startLatch.countDown() 完成时,“evaluate() 线程”会被阻塞,但测试方法可能会在上下文切换回“evaluate() 线程”之前开始运行。在“evaluate()线程”再次被唤醒后,它调用FutureTask.get(),这将阻塞“evaluate()线程”,但不能保证“CallableStatement线程”在此之后立即被唤醒。
所以,我认为测试方法开始的那一刻与task.get(timeout, timeUnit) 被调用的那一刻无关。如果有很多其他线程,它们之间的时间间隔可以忽略不计。
【问题讨论】:
标签: java junit concurrency