Я предполагаю, что вы имеете в виду метод, который я нашел в сети:
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
V content = null;
try {
if (innerFuture != null) {
content = innerFuture.get(timeout, unit);
}
} catch (TimeoutException t) {
if (!contentProcessed.get() && timeout != -1 && ((System.currentTimeMillis() - touch.get()) <= responseTimeoutInMs)) {
return get(timeout, unit);
}
if (exception.get() == null) {
timedOut.set(true);
throw new ExecutionException(new TimeoutException(String.format("No response received after %s", responseTimeoutInMs)));
}
} catch (CancellationException ce) {
}
if (exception.get() != null) {
throw new ExecutionException(exception.get());
}
return content;
}
Вы можете считать этот класс ошибочным в нескольких отношениях. Первая ошибка, которая сразу бросается в глаза, это использование System.currentTimeMillis()
вместо System.nanoTime()
. System.currentTimeMillis()
относится к системным часам компьютера, которые могут быть скорректированы во время выполнения программ и, следовательно, могут прыгать вперед и назад. Код, работающий с тайм-аутами, должен использовать System.nanoTime()
, что дает значение, относящееся к выполнению программы, независимое от часов реального мира.
responseTimeoutInMs
, по-видимому, подразумевается как тайм-аут соединения, но его использование, даже когда timeout
, переданное в качестве значения параметра, истекло, является нарушением контракта Future
. Правильным поведением было бы истечение времени ожидания метода get
, даже если задача, представленная Future
, все еще может выполняться.
Но рекурсивный вызов метода get
— двойная ошибка. Рекурсия опасна не только тем, что малые значения времени ожидания могут привести к StackOverflowError
; повторная передача одного и того же timeout
самому себе означает бесконечную отсрочку тайм-аута, поскольку каждый повторный вызов будет рассматривать это значение как относительно текущего времени.
Интересно, что даже если метод достигает точки тайм-аута, он заключает TimeoutException
в ExecutionException
, сообщая вызывающей программе совершенно неправильную семантику.
Я не верю, что вы найдете кого-то на stackoverflow, кто может объяснить причину этой реализации, если она вообще существует. Вам нужно будет напрямую обратиться к сторонникам / авторам этого кода.
person
Holger
schedule
06.11.2013