在AsyncHttpClient JDKFuture.get()
中 public V [More ...] get(long timeout, TimeUnit unit) {
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);
}
为什么我们有2次超时?
1. timeout as param
2. responseTimeoutInMs
第二次超时对我们造成伤害,因为即使在超时到期后呼叫也没有出现。它不断递归地调用get()。
一旦命中了responseTimeoutInMs,连接是否会关闭?我们试图将其设置为低于超时。
答案 0 :(得分:2)
我假设你指的是我在网上找到的方法:
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上有人可以解释这个实现背后的基本原理,如果有的话。您将不得不直接询问该代码的支持者/作者。
答案 1 :(得分:0)
不要使用JDK提供商,它已被破坏并被放入AHC 2.使用Netty,并升级到现代版本。