001/* 002 * Copyright (C) 2018 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.util.concurrent; 016 017import static com.google.common.base.Preconditions.checkNotNull; 018import static com.google.common.base.Preconditions.checkState; 019import static com.google.common.util.concurrent.ExecutionSequencer.RunningState.NOT_RUN; 020import static com.google.common.util.concurrent.ExecutionSequencer.RunningState.STARTED; 021import static com.google.common.util.concurrent.ExecutionSequencer.RunningState.WILL_NOT_RUN; 022import static com.google.common.util.concurrent.Futures.immediateCancelledFuture; 023import static com.google.common.util.concurrent.Futures.immediateFuture; 024import static com.google.common.util.concurrent.Futures.immediateVoidFuture; 025import static com.google.common.util.concurrent.MoreExecutors.directExecutor; 026import static java.util.Objects.requireNonNull; 027 028import com.google.common.annotations.GwtIncompatible; 029import com.google.common.annotations.J2ktIncompatible; 030import com.google.errorprone.annotations.concurrent.LazyInit; 031import java.util.concurrent.Callable; 032import java.util.concurrent.Executor; 033import java.util.concurrent.Future; 034import java.util.concurrent.RejectedExecutionException; 035import java.util.concurrent.atomic.AtomicReference; 036import org.jspecify.annotations.Nullable; 037 038/** 039 * Serializes execution of tasks, somewhat like an "asynchronous {@code synchronized} block." Each 040 * {@linkplain #submit enqueued} callable will not be submitted to its associated executor until the 041 * previous callable has returned -- and, if the previous callable was an {@link AsyncCallable}, not 042 * until the {@code Future} it returned is {@linkplain Future#isDone done} (successful, failed, or 043 * cancelled). 044 * 045 * <p>This class serializes execution of <i>submitted</i> tasks but not any <i>listeners</i> of 046 * those tasks. 047 * 048 * <p>Submitted tasks have a happens-before order as defined in the Java Language Specification. 049 * Tasks execute with the same happens-before order that the function calls to {@link #submit} and 050 * {@link #submitAsync} that submitted those tasks had. 051 * 052 * <p>This class has limited support for cancellation and other "early completions": 053 * 054 * <ul> 055 * <li>While calls to {@code submit} and {@code submitAsync} return a {@code Future} that can be 056 * cancelled, cancellation never propagates to a task that has started to run -- neither to 057 * the callable itself nor to any {@code Future} returned by an {@code AsyncCallable}. 058 * (However, cancellation can prevent an <i>unstarted</i> task from running.) Therefore, the 059 * next task will wait for any running callable (or pending {@code Future} returned by an 060 * {@code AsyncCallable}) to complete, without interrupting it (and without calling {@code 061 * cancel} on the {@code Future}). So beware: <i>Even if you cancel every preceding {@code 062 * Future} returned by this class, the next task may still have to wait.</i>. 063 * <li>Once an {@code AsyncCallable} returns a {@code Future}, this class considers that task to 064 * be "done" as soon as <i>that</i> {@code Future} completes in any way. Notably, a {@code 065 * Future} is "completed" even if it is cancelled while its underlying work continues on a 066 * thread, an RPC, etc. The {@code Future} is also "completed" if it fails "early" -- for 067 * example, if the deadline expires on a {@code Future} returned from {@link 068 * Futures#withTimeout} while the {@code Future} it wraps continues its underlying work. So 069 * beware: <i>Your {@code AsyncCallable} should not complete its {@code Future} until it is 070 * safe for the next task to start.</i> 071 * </ul> 072 * 073 * <p>This class is similar to {@link MoreExecutors#newSequentialExecutor}. This class is different 074 * in a few ways: 075 * 076 * <ul> 077 * <li>Each task may be associated with a different executor. 078 * <li>Tasks may be of type {@code AsyncCallable}. 079 * <li>Running tasks <i>cannot</i> be interrupted. (Note that {@code newSequentialExecutor} does 080 * not return {@code Future} objects, so it doesn't support interruption directly, either. 081 * However, utilities that <i>use</i> that executor have the ability to interrupt tasks 082 * running on it. This class, by contrast, does not expose an {@code Executor} API.) 083 * </ul> 084 * 085 * <p>If you don't need the features of this class, you may prefer {@code newSequentialExecutor} for 086 * its simplicity and ability to accommodate interruption. 087 * 088 * @since 26.0 089 */ 090@J2ktIncompatible 091@GwtIncompatible 092public final class ExecutionSequencer { 093 094 private ExecutionSequencer() {} 095 096 /** Creates a new instance. */ 097 public static ExecutionSequencer create() { 098 return new ExecutionSequencer(); 099 } 100 101 /** This reference acts as a pointer tracking the head of a linked list of ListenableFutures. */ 102 private final AtomicReference<ListenableFuture<@Nullable Void>> ref = 103 new AtomicReference<>(immediateVoidFuture()); 104 105 @LazyInit private ThreadConfinedTaskQueue latestTaskQueue = new ThreadConfinedTaskQueue(); 106 107 /** 108 * This object is unsafely published, but avoids problematic races by relying exclusively on the 109 * identity equality of its Thread field so that the task field is only accessed by a single 110 * thread. 111 */ 112 private static final class ThreadConfinedTaskQueue { 113 /** 114 * This field is only used for identity comparisons with the current thread. Field assignments 115 * are atomic, but do not provide happens-before ordering; however: 116 * 117 * <ul> 118 * <li>If this field's value == currentThread, we know that it's up to date, because write 119 * operations in a thread always happen-before subsequent read operations in the same 120 * thread 121 * <li>If this field's value == null because of unsafe publication, we know that it isn't the 122 * object associated with our thread, because if it was the publication wouldn't have been 123 * unsafe and we'd have seen our thread as the value. This state is also why a new 124 * ThreadConfinedTaskQueue object must be created for each inline execution, because 125 * observing a null thread does not mean the object is safe to reuse. 126 * <li>If this field's value is some other thread object, we know that it's not our thread. 127 * <li>If this field's value == null because it originally belonged to another thread and that 128 * thread cleared it, we still know that it's not associated with our thread 129 * <li>If this field's value == null because it was associated with our thread and was 130 * cleared, we know that we're not executing inline any more 131 * </ul> 132 * 133 * All the states where thread != currentThread are identical for our purposes, and so even 134 * though it's racy, we don't care which of those values we get, so no need to synchronize. 135 */ 136 @LazyInit @Nullable Thread thread; 137 138 /** Only used by the thread associated with this object */ 139 @Nullable TrustedListenableFutureTask<?> nextTask; 140 141 /** Only used by the thread associated with this object */ 142 @Nullable Executor nextExecutor; 143 } 144 145 /** 146 * Enqueues a task to run when the previous task (if any) completes. 147 * 148 * <p>Cancellation does not propagate from the output future to a callable that has begun to 149 * execute, but if the output future is cancelled before {@link Callable#call()} is invoked, 150 * {@link Callable#call()} will not be invoked. 151 */ 152 public <T extends @Nullable Object> ListenableFuture<T> submit( 153 Callable<T> callable, Executor executor) { 154 checkNotNull(callable); 155 checkNotNull(executor); 156 return submitAsync( 157 new AsyncCallable<T>() { 158 @Override 159 public ListenableFuture<T> call() throws Exception { 160 return immediateFuture(callable.call()); 161 } 162 163 @Override 164 public String toString() { 165 return callable.toString(); 166 } 167 }, 168 executor); 169 } 170 171 /** 172 * Enqueues a task to run when the previous task (if any) completes. 173 * 174 * <p>Cancellation does not propagate from the output future to the future returned from {@code 175 * callable} or a callable that has begun to execute, but if the output future is cancelled before 176 * {@link AsyncCallable#call()} is invoked, {@link AsyncCallable#call()} will not be invoked. 177 */ 178 public <T extends @Nullable Object> ListenableFuture<T> submitAsync( 179 AsyncCallable<T> callable, Executor executor) { 180 checkNotNull(callable); 181 checkNotNull(executor); 182 TaskNonReentrantExecutor taskExecutor = new TaskNonReentrantExecutor(executor, this); 183 AsyncCallable<T> task = 184 new AsyncCallable<T>() { 185 @Override 186 public ListenableFuture<T> call() throws Exception { 187 if (!taskExecutor.trySetStarted()) { 188 return immediateCancelledFuture(); 189 } 190 return callable.call(); 191 } 192 193 @Override 194 public String toString() { 195 return callable.toString(); 196 } 197 }; 198 /* 199 * Four futures are at play here: 200 * taskFuture is the future tracking the result of the callable. 201 * newFuture is a future that completes after this and all prior tasks are done. 202 * oldFuture is the previous task's newFuture. 203 * outputFuture is the future we return to the caller, a nonCancellationPropagating taskFuture. 204 * 205 * newFuture is guaranteed to only complete once all tasks previously submitted to this instance 206 * have completed - namely after oldFuture is done, and taskFuture has either completed or been 207 * cancelled before the callable started execution. 208 */ 209 SettableFuture<@Nullable Void> newFuture = SettableFuture.create(); 210 211 ListenableFuture<@Nullable Void> oldFuture = ref.getAndSet(newFuture); 212 213 // Invoke our task once the previous future completes. 214 TrustedListenableFutureTask<T> taskFuture = TrustedListenableFutureTask.create(task); 215 oldFuture.addListener(taskFuture, taskExecutor); 216 217 ListenableFuture<T> outputFuture = Futures.nonCancellationPropagating(taskFuture); 218 219 // newFuture's lifetime is determined by taskFuture, which can't complete before oldFuture 220 // unless taskFuture is cancelled, in which case it falls back to oldFuture. This ensures that 221 // if the future we return is cancelled, we don't begin execution of the next task until after 222 // oldFuture completes. 223 Runnable listener = 224 () -> { 225 if (taskFuture.isDone()) { 226 // Since the value of oldFuture can only ever be immediateVoidFuture() or setFuture of a 227 // future that eventually came from immediateVoidFuture(), this doesn't leak throwables 228 // or completion values. 229 newFuture.setFutureInternal(oldFuture); 230 } else if (outputFuture.isCancelled() && taskExecutor.trySetCancelled()) { 231 // If this CAS succeeds, we know that the provided callable will never be invoked, 232 // so when oldFuture completes it is safe to allow the next submitted task to 233 // proceed. Doing this immediately here lets the next task run without waiting for 234 // the cancelled task's executor to run the noop AsyncCallable. 235 // 236 // --- 237 // 238 // If the CAS fails, the provided callable already started running (or it is about 239 // to). Our contract promises: 240 // 241 // 1. not to execute a new callable until the old one has returned 242 // 243 // If we were to cancel taskFuture, that would let the next task start while the old 244 // one is still running. 245 // 246 // Now, maybe we could tweak our implementation to not start the next task until the 247 // callable actually completes. (We could detect completion in our wrapper 248 // `AsyncCallable task`.) However, our contract also promises: 249 // 250 // 2. not to cancel any Future the user returned from an AsyncCallable 251 // 252 // We promise this because, once we cancel that Future, we would no longer be able to 253 // tell when any underlying work it is doing is done. Thus, we might start a new task 254 // while that underlying work is still running. 255 // 256 // So that is why we cancel only in the case of CAS success. 257 taskFuture.cancel(false); 258 } 259 }; 260 // Adding the listener to both futures guarantees that newFuture will always be set. Adding to 261 // taskFuture guarantees completion if the callable is invoked, and adding to outputFuture 262 // propagates cancellation if the callable has not yet been invoked. 263 outputFuture.addListener(listener, directExecutor()); 264 taskFuture.addListener(listener, directExecutor()); 265 266 return outputFuture; 267 } 268 269 enum RunningState { 270 NOT_RUN, 271 WILL_NOT_RUN, 272 STARTED, 273 } 274 275 /** 276 * This class helps avoid a StackOverflowError when large numbers of tasks are submitted with 277 * {@link MoreExecutors#directExecutor}. Normally, when the first future completes, all the other 278 * tasks would be called recursively. Here, we detect that the delegate executor is executing 279 * inline, and maintain a queue to dispatch tasks iteratively. There is one instance of this class 280 * per call to submit() or submitAsync(), and each instance supports only one call to execute(). 281 * 282 * <p>This class would certainly be simpler and easier to reason about if it were built with 283 * ThreadLocal; however, ThreadLocal is not well optimized for the case where the ThreadLocal is 284 * non-static, and is initialized/removed frequently - this causes churn in the Thread specific 285 * hashmaps. Using a static ThreadLocal to avoid that overhead would mean that different 286 * ExecutionSequencer objects interfere with each other, which would be undesirable, in addition 287 * to increasing the memory footprint of every thread that interacted with it. In order to release 288 * entries in thread-specific maps when the ThreadLocal object itself is no longer referenced, 289 * ThreadLocal is usually implemented with a WeakReference, which can have negative performance 290 * properties; for example, calling WeakReference.get() on Android will block during an 291 * otherwise-concurrent GC cycle. 292 */ 293 private static final class TaskNonReentrantExecutor extends AtomicReference<RunningState> 294 implements Executor, Runnable { 295 296 /** 297 * Used to update and read the latestTaskQueue field. Set to null once the runnable has been run 298 * or queued. 299 */ 300 @Nullable ExecutionSequencer sequencer; 301 302 /** 303 * Executor the task was set to run on. Set to null when the task has been queued, run, or 304 * cancelled. 305 */ 306 @Nullable Executor delegate; 307 308 /** 309 * Set before calling delegate.execute(); set to null once run, so that it can be GCed; this 310 * object may live on after, if submitAsync returns an incomplete future. 311 */ 312 @Nullable TrustedListenableFutureTask<?> task; 313 314 /** Thread that called execute(). Set in execute, cleared when delegate.execute() returns. */ 315 @LazyInit @Nullable Thread submitting; 316 317 private TaskNonReentrantExecutor(Executor delegate, ExecutionSequencer sequencer) { 318 super(NOT_RUN); 319 this.delegate = delegate; 320 this.sequencer = sequencer; 321 } 322 323 /* 324 * We compare two Thread instances with ==: For concurrency correctness, we need to know whether 325 * they are actually the same thread, even if they are instances of some user subclass that 326 * overrides Thread.equals. 327 */ 328 @SuppressWarnings("ReferenceEquality") 329 @Override 330 public void execute(Runnable task) { 331 // If this operation was successfully cancelled already, calling the runnable will be a noop. 332 // This also avoids a race where if outputFuture is cancelled, it will call taskFuture.cancel, 333 // which will call newFuture.setFuture(oldFuture), to allow the next task in the queue to run 334 // without waiting for the user's executor to run our submitted Runnable. However, this can 335 // interact poorly with the reentrancy-avoiding behavior of this executor - when the operation 336 // before the cancelled future completes, it will synchronously complete both the newFuture 337 // from the cancelled operation and its own. This can cause one runnable to queue two tasks, 338 // breaking the invariant this method relies on to iteratively run the next task after the 339 // previous one completes. 340 if (get() == RunningState.WILL_NOT_RUN) { 341 delegate = null; 342 sequencer = null; 343 return; 344 } 345 submitting = Thread.currentThread(); 346 TrustedListenableFutureTask<?> trustedFutureTask = (TrustedListenableFutureTask<?>) task; 347 348 try { 349 /* 350 * requireNonNull is safe because we don't null out `sequencer` except: 351 * 352 * - above, where we return (in which case we never get here) 353 * 354 * - in `run`, which can't run until this Runnable is submitted to an executor, which 355 * doesn't happen until below. (And this Executor -- yes, the object is both a Runnable 356 * and an Executor -- is used for only a single `execute` call.) 357 */ 358 ThreadConfinedTaskQueue submittingTaskQueue = requireNonNull(sequencer).latestTaskQueue; 359 if (submittingTaskQueue.thread == submitting) { 360 sequencer = null; 361 // Submit from inside a reentrant submit. We don't know if this one will be reentrant (and 362 // can't know without submitting something to the executor) so queue to run iteratively. 363 // Task must be null, since each execution on this executor can only produce one more 364 // execution. 365 checkState(submittingTaskQueue.nextTask == null); 366 submittingTaskQueue.nextTask = trustedFutureTask; 367 // requireNonNull(delegate) is safe for reasons similar to requireNonNull(sequencer). 368 submittingTaskQueue.nextExecutor = requireNonNull(delegate); 369 delegate = null; 370 } else { 371 // requireNonNull(delegate) is safe for reasons similar to requireNonNull(sequencer). 372 Executor localDelegate = requireNonNull(delegate); 373 delegate = null; 374 this.task = trustedFutureTask; 375 try { 376 localDelegate.execute(this); 377 } catch (RejectedExecutionException e) { 378 /* 379 * `trySetCancelled` is irrelevant when we know the task won't run and when it is 380 * harmless for our `setExceptionInternal` call here to race with a user call to 381 * `cancel`. But we do it anyway in case we want to use the `RunningState` for another 382 * purpose someday. 383 */ 384 boolean unused = trySetCancelled(); 385 trustedFutureTask.setExceptionInternal(e); 386 /* 387 * We don't need to clear `this.task` because no one will have a 388 * reference to `this` after we return. 389 */ 390 } 391 } 392 } finally { 393 // Important to null this out here - if we did *not* execute inline, we might still 394 // run() on the same thread that called execute() - such as in a thread pool, and think 395 // that it was happening inline. As a side benefit, avoids holding on to the Thread object 396 // longer than necessary. 397 submitting = null; 398 } 399 } 400 401 @SuppressWarnings({ 402 "ShortCircuitBoolean", 403 /* 404 * We compare two Thread instances with ==: For concurrency correctness, we need to know 405 * whether they are actually the same thread, even if they are instances of some user subclass 406 * that overrides Thread.equals. 407 */ 408 "ReferenceEquality", 409 }) 410 @Override 411 public void run() { 412 Thread currentThread = Thread.currentThread(); 413 if (currentThread != submitting) { 414 /* 415 * requireNonNull is safe because we set `task` before submitting this Runnable to an 416 * Executor, and we don't null it out until here. 417 */ 418 Runnable localTask = requireNonNull(task); 419 task = null; 420 localTask.run(); 421 return; 422 } 423 // Executor called reentrantly! Make sure that further calls don't overflow stack. Further 424 // reentrant calls will see that their current thread is the same as the one set in 425 // latestTaskQueue, and queue rather than calling execute() directly. 426 ThreadConfinedTaskQueue executingTaskQueue = new ThreadConfinedTaskQueue(); 427 executingTaskQueue.thread = currentThread; 428 /* 429 * requireNonNull is safe because we don't null out `sequencer` except: 430 * 431 * - after the requireNonNull call below. (And this object has its Runnable.run override 432 * called only once, just as it has its Executor.execute override called only once.) 433 * 434 * - if we return immediately from `execute` (in which case we never get here) 435 * 436 * - in the "reentrant submit" case of `execute` (in which case we must have started running a 437 * user task -- which means that we already got past this code (or else we exited early 438 * above)) 439 */ 440 // Unconditionally set; there is no risk of throwing away a queued task from another thread, 441 // because in order for the current task to run on this executor the previous task must have 442 // already started execution. Because each task on a TaskNonReentrantExecutor can only produce 443 // one execute() call to another instance from the same ExecutionSequencer, we know by 444 // induction that the task that launched this one must not have added any other runnables to 445 // that thread's queue, and thus we cannot be replacing a TaskAndThread object that would 446 // otherwise have another task queued on to it. Note the exception to this, cancellation, is 447 // specially handled in execute() - execute() calls triggered by cancellation are no-ops, and 448 // thus don't count. 449 requireNonNull(sequencer).latestTaskQueue = executingTaskQueue; 450 sequencer = null; 451 try { 452 // requireNonNull is safe, as discussed above. 453 Runnable localTask = requireNonNull(task); 454 task = null; 455 localTask.run(); 456 // Now check if our task attempted to reentrantly execute the next task. 457 TrustedListenableFutureTask<?> queuedTask; 458 Executor queuedExecutor; 459 /* 460 * We used to use a non-short-circuit operator here as a nano-optimization, but it caused 461 * trouble for some transpiled compilation. 462 */ 463 while ((queuedTask = executingTaskQueue.nextTask) != null 464 && (queuedExecutor = executingTaskQueue.nextExecutor) != null) { 465 executingTaskQueue.nextTask = null; 466 executingTaskQueue.nextExecutor = null; 467 try { 468 queuedExecutor.execute(queuedTask); 469 } catch (RejectedExecutionException e) { 470 queuedTask.setExceptionInternal(e); 471 } 472 } 473 } finally { 474 // Null out the thread field, so that we don't leak a reference to Thread, and so that 475 // future `thread == currentThread()` calls from this thread don't incorrectly queue instead 476 // of executing. Don't null out the latestTaskQueue field, because the work done here 477 // may have scheduled more operations on another thread, and if those operations then 478 // trigger reentrant calls that thread will have updated the latestTaskQueue field, and 479 // we'd be interfering with their operation. 480 executingTaskQueue.thread = null; 481 } 482 } 483 484 private boolean trySetStarted() { 485 return compareAndSet(NOT_RUN, STARTED); 486 } 487 488 private boolean trySetCancelled() { 489 return compareAndSet(NOT_RUN, WILL_NOT_RUN); 490 } 491 } 492}