私がネットで見つけた方法を参照していると思います。
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にいるとは思わない。そのコードのサポーター/作者に直接尋ねる必要があります。