()
| 90 | } |
| 91 | |
| 92 | @Override |
| 93 | public void run() { |
| 94 | // If either of these reads return null then we must be after a successful cancel or another |
| 95 | // call to this method. |
| 96 | TimeoutFuture<V> timeoutFuture = timeoutFutureRef; |
| 97 | if (timeoutFuture == null) { |
| 98 | return; |
| 99 | } |
| 100 | ListenableFuture<V> delegate = timeoutFuture.delegateRef; |
| 101 | if (delegate == null) { |
| 102 | return; |
| 103 | } |
| 104 | |
| 105 | /* |
| 106 | * If we're about to complete the TimeoutFuture, we want to release our reference to it. |
| 107 | * Otherwise, we'll pin it (and its result) in memory until the timeout task is GCed. (The |
| 108 | * need to clear our reference to the TimeoutFuture is the reason we use a *static* nested |
| 109 | * class with a manual reference back to the "containing" class.) |
| 110 | * |
| 111 | * This has the nice-ish side effect of limiting reentrancy: run() calls |
| 112 | * timeoutFuture.setException() calls run(). That reentrancy would already be harmless, since |
| 113 | * timeoutFuture can be set (and delegate cancelled) only once. (And "set only once" is |
| 114 | * important for other reasons: run() can still be invoked concurrently in different threads, |
| 115 | * even with the above null checks.) |
| 116 | */ |
| 117 | timeoutFutureRef = null; |
| 118 | if (delegate.isDone()) { |
| 119 | timeoutFuture.setFuture(delegate); |
| 120 | } else { |
| 121 | try { |
| 122 | // TODO(lukes): this stack trace is particularly useless (all it does is point at the |
| 123 | // scheduledexecutorservice thread), consider eliminating it altogether? |
| 124 | timeoutFuture.setException(new TimeoutException("Future timed out: " + delegate)); |
| 125 | } finally { |
| 126 | delegate.cancel(true); |
| 127 | } |
| 128 | } |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | @Override |
nothing calls this directly
no test coverage detected