Я только начал читать код JUnit 4.13 (https://github.com/junit-team/junit), и получить немного запутался об осуществлении org.junit.internal.runners.statements.FailOnTimeout
:Почему JUnit с помощью CountDownLatch реализовать 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()
)? Есть ли «более простой» способ сделать это?
Я не очень знаком с параллелизмом. И я был бы очень признателен, если кто-нибудь сможет объяснить это или указать мои ошибки. Благодарю.
Больше объяснения по поводу второго вопроса:
Я бы обозначить две темы, как «оценка() нить» и «CallableStatement нить».
Я думаю, что «Оценить() поток» заблокирован, когда callable.awaitStarted()
выполняется до тех пор, пока не будет выполнено startLatch.countDown()
, но метод тестирования может начать работать до того, как контекст переключится на «оценить() поток». Сразу после того, как «review() thread« снова пробуждается », он вызывает FutureTask.get()
, который блокирует« поток()() », но не может гарантировать, что« CallableStatement thread »будет пробужден сразу после этого.
Итак, я думаю, что момент начала тестового метода не имеет ничего общего с моментом task.get(timeout, timeUnit)
. Если есть много других потоков, между ними может быть нерегулярный временной интервал.
Большое спасибо за ваш совет, теперь я понимаю поток Daemon. По второму вопросу, я отредактировал свой пост с еще одним объяснением, надеюсь, что вы могли бы ответить на это. Еще раз спасибо. – Morrissss
Вы частично правы: «Если есть много других потоков, между ними может быть нерегулярный промежуток времени». таким образом, что может потребоваться некоторое время для переключения контекстов, но на практике, если в потоке Runnable не слишком много потоков, и большинство потоков имеют одинаковый приоритет, это должен быть незначительный временной интервал. Также я бы предположил, что «тайм-аут» не предназначен как инструмент для измерения времени, а скорее как безопасность для неправильной работы потоков. – JiriS
'FailOnTimeout' используется для проверки того, может ли тестовый метод завершиться в' timeout'. Поэтому «timeout» используется для измерения времени. Я думаю, что 'callable.awaitStarted()' не может помешать запуску тестового метода, а 'task.get()' не может предотвратить пробуждение других потоков, кроме потока CallableStatement. Поэтому 'CountDownLatch' не работает лучше, чем просто используя' FutureTask', и желая, чтобы это было пробуждено как можно скорее. – Morrissss