001/* 002 * Copyright (C) 2011 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.Verify.verify; 018import static com.google.common.util.concurrent.Internal.toNanosSaturated; 019import static java.util.concurrent.TimeUnit.NANOSECONDS; 020 021import com.google.common.annotations.GwtCompatible; 022import com.google.common.annotations.GwtIncompatible; 023import com.google.common.annotations.J2ktIncompatible; 024import com.google.common.base.Preconditions; 025import com.google.errorprone.annotations.CanIgnoreReturnValue; 026import java.time.Duration; 027import java.util.concurrent.BlockingQueue; 028import java.util.concurrent.CancellationException; 029import java.util.concurrent.CountDownLatch; 030import java.util.concurrent.ExecutionException; 031import java.util.concurrent.ExecutorService; 032import java.util.concurrent.Future; 033import java.util.concurrent.Semaphore; 034import java.util.concurrent.TimeUnit; 035import java.util.concurrent.TimeoutException; 036import java.util.concurrent.locks.Condition; 037import java.util.concurrent.locks.Lock; 038import org.jspecify.annotations.Nullable; 039 040/** 041 * Utilities for treating interruptible operations as uninterruptible. In all cases, if a thread is 042 * interrupted during such a call, the call continues to block until the result is available or the 043 * timeout elapses, and only then re-interrupts the thread. 044 * 045 * @author Anthony Zana 046 * @since 10.0 047 */ 048@GwtCompatible 049public final class Uninterruptibles { 050 /** Invokes {@code latch.}{@link CountDownLatch#await() await()} uninterruptibly. */ 051 @J2ktIncompatible 052 @GwtIncompatible // concurrency 053 public static void awaitUninterruptibly(CountDownLatch latch) { 054 boolean interrupted = false; 055 try { 056 while (true) { 057 try { 058 latch.await(); 059 return; 060 } catch (InterruptedException e) { 061 interrupted = true; 062 } 063 } 064 } finally { 065 if (interrupted) { 066 Thread.currentThread().interrupt(); 067 } 068 } 069 } 070 071 /** 072 * Invokes {@code latch.}{@link CountDownLatch#await(long, TimeUnit) await(timeout, unit)} 073 * uninterruptibly. 074 * 075 * @since 28.0 (but only since 33.4.0 in the Android flavor) 076 */ 077 @J2ktIncompatible 078 @GwtIncompatible // concurrency 079 public static boolean awaitUninterruptibly(CountDownLatch latch, Duration timeout) { 080 return awaitUninterruptibly(latch, toNanosSaturated(timeout), NANOSECONDS); 081 } 082 083 /** 084 * Invokes {@code latch.}{@link CountDownLatch#await(long, TimeUnit) await(timeout, unit)} 085 * uninterruptibly. 086 */ 087 @J2ktIncompatible 088 @GwtIncompatible // concurrency 089 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 090 public static boolean awaitUninterruptibly(CountDownLatch latch, long timeout, TimeUnit unit) { 091 boolean interrupted = false; 092 try { 093 long remainingNanos = unit.toNanos(timeout); 094 long end = System.nanoTime() + remainingNanos; 095 096 while (true) { 097 try { 098 // CountDownLatch treats negative timeouts just like zero. 099 return latch.await(remainingNanos, NANOSECONDS); 100 } catch (InterruptedException e) { 101 interrupted = true; 102 remainingNanos = end - System.nanoTime(); 103 } 104 } 105 } finally { 106 if (interrupted) { 107 Thread.currentThread().interrupt(); 108 } 109 } 110 } 111 112 /** 113 * Invokes {@code condition.}{@link Condition#await(long, TimeUnit) await(timeout, unit)} in a way 114 * that more conveniently supports uninterruptible waits. 115 * 116 * <p>If the underlying {@code await} call is interrupted, then {@code awaitUninterruptibly} 117 * converts that into a {@linkplain Condition##implementation-considerations-heading spurious 118 * wakeup}. This means that resulting wait is not "uninterruptible" in the normal sense of {@link 119 * Uninterruptibles}. Still, this method allows callers to write <a 120 * href="https://errorprone.info/bugpattern/WaitNotInLoop">the standard, required loop for waiting on a {@code 121 * Condition}</a> but without the need to handle interruption. 122 * 123 * @return {@code false} if the waiting time detectably elapsed before return from the method 124 * @since 28.0 (but only since 33.4.0 in the Android flavor) 125 */ 126 @J2ktIncompatible 127 @GwtIncompatible // concurrency 128 public static boolean awaitUninterruptibly(Condition condition, Duration timeout) { 129 return awaitUninterruptibly(condition, toNanosSaturated(timeout), NANOSECONDS); 130 } 131 132 /** 133 * Invokes {@code condition.}{@link Condition#await(long, TimeUnit) await(timeout, unit)} in a way 134 * that more conveniently supports uninterruptible waits. 135 * 136 * <p>If the underlying {@code await} call is interrupted, then {@code awaitUninterruptibly} 137 * converts that into a {@linkplain Condition##implementation-considerations-heading spurious 138 * wakeup}. This means that resulting wait is not "uninterruptible" in the normal sense of {@link 139 * Uninterruptibles}. Still, this method allows callers to write <a 140 * href="https://errorprone.info/bugpattern/WaitNotInLoop">the standard, required loop for waiting on a {@code 141 * Condition}</a> but without the need to handle interruption. 142 * 143 * @return {@code false} if the waiting time detectably elapsed before return from the method 144 * @since 23.6 145 */ 146 @J2ktIncompatible 147 @GwtIncompatible // concurrency 148 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 149 public static boolean awaitUninterruptibly(Condition condition, long timeout, TimeUnit unit) { 150 /* 151 * An uninterruptible wait on a Condition requires different logic than an uninterruptible wait 152 * on most other types: In cases in which we "should" receive both an interrupt and a 153 * notification nearly simultaneously, we sometimes receive only an interrupt. Thus, when we're 154 * interrupted, we can't just poll whether it's time to end the wait because our "end the wait" 155 * notification has been lost. (This is in contrast to how we can poll with, say, a 156 * CountDownLatch.) In order to avoid hiding the requested notification from the caller, we need 157 * to return. Fortunately, a wait on a Condition is allowed to return early on account of a 158 * "spurious wakeup," so we're allowed to convert interruptions into such wakeups. 159 */ 160 161 /* 162 * Since we can't loop inside awaitUninterruptibly(Condition, ...), the user is responsible for 163 * calling us again in case of interrupt. Then, if we were to call await(...) immediately, as we 164 * do in the other Uninterruptibles methods, it would throw immediately. Then we'd restore the 165 * interrupt and return again, and the user would call us again, creating a busy wait. 166 * 167 * Thus, we need to clear the interrupt eagerly in case it's an interrupt from a previous call 168 * to awaitUninterruptibly in the user code's Condition loop. 169 */ 170 boolean wasAlreadyInterrupted = Thread.interrupted(); 171 long remainingNanos = unit.toNanos(timeout); 172 long end = System.nanoTime() + remainingNanos; 173 174 try { 175 boolean result = condition.await(remainingNanos, NANOSECONDS); 176 if (wasAlreadyInterrupted) { 177 Thread.currentThread().interrupt(); 178 } 179 return result; 180 } catch (InterruptedException e) { 181 Thread.currentThread().interrupt(); 182 // better than `end > System.nanoTime()` because `System.nanoTime()` could wrap around 183 return end - System.nanoTime() > 0; 184 } 185 } 186 187 /** Invokes {@code toJoin.}{@link Thread#join() join()} uninterruptibly. */ 188 @J2ktIncompatible 189 @GwtIncompatible // concurrency 190 public static void joinUninterruptibly(Thread toJoin) { 191 boolean interrupted = false; 192 try { 193 while (true) { 194 try { 195 toJoin.join(); 196 return; 197 } catch (InterruptedException e) { 198 interrupted = true; 199 } 200 } 201 } finally { 202 if (interrupted) { 203 Thread.currentThread().interrupt(); 204 } 205 } 206 } 207 208 /** 209 * Invokes {@code unit.}{@link TimeUnit#timedJoin(Thread, long) timedJoin(toJoin, timeout)} 210 * uninterruptibly. 211 * 212 * @since 28.0 (but only since 33.4.0 in the Android flavor) 213 */ 214 @J2ktIncompatible 215 @GwtIncompatible // concurrency 216 public static void joinUninterruptibly(Thread toJoin, Duration timeout) { 217 joinUninterruptibly(toJoin, toNanosSaturated(timeout), NANOSECONDS); 218 } 219 220 /** 221 * Invokes {@code unit.}{@link TimeUnit#timedJoin(Thread, long) timedJoin(toJoin, timeout)} 222 * uninterruptibly. 223 */ 224 @J2ktIncompatible 225 @GwtIncompatible // concurrency 226 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 227 public static void joinUninterruptibly(Thread toJoin, long timeout, TimeUnit unit) { 228 Preconditions.checkNotNull(toJoin); 229 boolean interrupted = false; 230 try { 231 long remainingNanos = unit.toNanos(timeout); 232 long end = System.nanoTime() + remainingNanos; 233 while (true) { 234 try { 235 // TimeUnit.timedJoin() treats negative timeouts just like zero. 236 NANOSECONDS.timedJoin(toJoin, remainingNanos); 237 return; 238 } catch (InterruptedException e) { 239 interrupted = true; 240 remainingNanos = end - System.nanoTime(); 241 } 242 } 243 } finally { 244 if (interrupted) { 245 Thread.currentThread().interrupt(); 246 } 247 } 248 } 249 250 /** 251 * Invokes {@code future.}{@link Future#get() get()} uninterruptibly. 252 * 253 * <p>Similar methods: 254 * 255 * <ul> 256 * <li>To retrieve a result from a {@code Future} that is already done, use {@link 257 * Futures#getDone Futures.getDone}. 258 * <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link 259 * Futures#getChecked(Future, Class) Futures.getChecked}. 260 * <li>To get uninterruptibility and remove checked exceptions, use {@link 261 * Futures#getUnchecked}. 262 * </ul> 263 * 264 * @throws ExecutionException if the computation threw an exception 265 * @throws CancellationException if the computation was cancelled 266 */ 267 @CanIgnoreReturnValue 268 @ParametricNullness 269 public static <V extends @Nullable Object> V getUninterruptibly(Future<V> future) 270 throws ExecutionException { 271 boolean interrupted = false; 272 try { 273 while (true) { 274 try { 275 return future.get(); 276 } catch (InterruptedException e) { 277 interrupted = true; 278 } 279 } 280 } finally { 281 if (interrupted) { 282 Thread.currentThread().interrupt(); 283 } 284 } 285 } 286 287 /** 288 * Invokes {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)} uninterruptibly. 289 * 290 * <p>Similar methods: 291 * 292 * <ul> 293 * <li>To retrieve a result from a {@code Future} that is already done, use {@link 294 * Futures#getDone Futures.getDone}. 295 * <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link 296 * Futures#getChecked(Future, Class, long, TimeUnit) Futures.getChecked}. 297 * <li>To get uninterruptibility and remove checked exceptions, use {@link 298 * Futures#getUnchecked}. 299 * </ul> 300 * 301 * @throws ExecutionException if the computation threw an exception 302 * @throws CancellationException if the computation was cancelled 303 * @throws TimeoutException if the wait timed out 304 * @since 28.0 (but only since 33.4.0 in the Android flavor) 305 */ 306 @CanIgnoreReturnValue 307 @J2ktIncompatible 308 @GwtIncompatible // java.time.Duration 309 @ParametricNullness 310 public static <V extends @Nullable Object> V getUninterruptibly( 311 Future<V> future, Duration timeout) throws ExecutionException, TimeoutException { 312 return getUninterruptibly(future, toNanosSaturated(timeout), NANOSECONDS); 313 } 314 315 /** 316 * Invokes {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)} uninterruptibly. 317 * 318 * <p>Similar methods: 319 * 320 * <ul> 321 * <li>To retrieve a result from a {@code Future} that is already done, use {@link 322 * Futures#getDone Futures.getDone}. 323 * <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link 324 * Futures#getChecked(Future, Class, long, TimeUnit) Futures.getChecked}. 325 * <li>To get uninterruptibility and remove checked exceptions, use {@link 326 * Futures#getUnchecked}. 327 * </ul> 328 * 329 * @throws ExecutionException if the computation threw an exception 330 * @throws CancellationException if the computation was cancelled 331 * @throws TimeoutException if the wait timed out 332 */ 333 @CanIgnoreReturnValue 334 @J2ktIncompatible 335 @GwtIncompatible // TODO 336 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 337 @ParametricNullness 338 public static <V extends @Nullable Object> V getUninterruptibly( 339 Future<V> future, long timeout, TimeUnit unit) throws ExecutionException, TimeoutException { 340 boolean interrupted = false; 341 try { 342 long remainingNanos = unit.toNanos(timeout); 343 long end = System.nanoTime() + remainingNanos; 344 345 while (true) { 346 try { 347 // Future treats negative timeouts just like zero. 348 return future.get(remainingNanos, NANOSECONDS); 349 } catch (InterruptedException e) { 350 interrupted = true; 351 remainingNanos = end - System.nanoTime(); 352 } 353 } 354 } finally { 355 if (interrupted) { 356 Thread.currentThread().interrupt(); 357 } 358 } 359 } 360 361 /** Invokes {@code queue.}{@link BlockingQueue#take() take()} uninterruptibly. */ 362 @J2ktIncompatible 363 @GwtIncompatible // concurrency 364 public static <E> E takeUninterruptibly(BlockingQueue<E> queue) { 365 boolean interrupted = false; 366 try { 367 while (true) { 368 try { 369 return queue.take(); 370 } catch (InterruptedException e) { 371 interrupted = true; 372 } 373 } 374 } finally { 375 if (interrupted) { 376 Thread.currentThread().interrupt(); 377 } 378 } 379 } 380 381 /** 382 * Invokes {@code queue.}{@link BlockingQueue#put(Object) put(element)} uninterruptibly. 383 * 384 * @throws ClassCastException if the class of the specified element prevents it from being added 385 * to the given queue 386 * @throws IllegalArgumentException if some property of the specified element prevents it from 387 * being added to the given queue 388 */ 389 @J2ktIncompatible 390 @GwtIncompatible // concurrency 391 public static <E> void putUninterruptibly(BlockingQueue<E> queue, E element) { 392 boolean interrupted = false; 393 try { 394 while (true) { 395 try { 396 queue.put(element); 397 return; 398 } catch (InterruptedException e) { 399 interrupted = true; 400 } 401 } 402 } finally { 403 if (interrupted) { 404 Thread.currentThread().interrupt(); 405 } 406 } 407 } 408 409 // TODO(b/5042178): Support Sleeper somehow (wrapper or interface method)? 410 /** 411 * Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)} uninterruptibly. 412 * 413 * @since 28.0 (but only since 33.4.0 in the Android flavor) 414 */ 415 @J2ktIncompatible 416 @GwtIncompatible // concurrency 417 public static void sleepUninterruptibly(Duration sleepFor) { 418 sleepUninterruptibly(toNanosSaturated(sleepFor), NANOSECONDS); 419 } 420 421 // TODO(b/5042178): Support Sleeper somehow (wrapper or interface method)? 422 /** Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)} uninterruptibly. */ 423 @J2ktIncompatible 424 @GwtIncompatible // concurrency 425 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 426 public static void sleepUninterruptibly(long sleepFor, TimeUnit unit) { 427 boolean interrupted = false; 428 try { 429 long remainingNanos = unit.toNanos(sleepFor); 430 long end = System.nanoTime() + remainingNanos; 431 while (true) { 432 try { 433 // TimeUnit.sleep() treats negative timeouts just like zero. 434 NANOSECONDS.sleep(remainingNanos); 435 return; 436 } catch (InterruptedException e) { 437 interrupted = true; 438 remainingNanos = end - System.nanoTime(); 439 } 440 } 441 } finally { 442 if (interrupted) { 443 Thread.currentThread().interrupt(); 444 } 445 } 446 } 447 448 /** 449 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(1, 450 * timeout, unit)} uninterruptibly. 451 * 452 * @since 28.0 (but only since 33.4.0 in the Android flavor) 453 */ 454 @J2ktIncompatible 455 @GwtIncompatible // concurrency 456 public static boolean tryAcquireUninterruptibly(Semaphore semaphore, Duration timeout) { 457 return tryAcquireUninterruptibly(semaphore, toNanosSaturated(timeout), NANOSECONDS); 458 } 459 460 /** 461 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(1, 462 * timeout, unit)} uninterruptibly. 463 * 464 * @since 18.0 465 */ 466 @J2ktIncompatible 467 @GwtIncompatible // concurrency 468 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 469 public static boolean tryAcquireUninterruptibly( 470 Semaphore semaphore, long timeout, TimeUnit unit) { 471 return tryAcquireUninterruptibly(semaphore, 1, timeout, unit); 472 } 473 474 /** 475 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(permits, 476 * timeout, unit)} uninterruptibly. 477 * 478 * @since 28.0 (but only since 33.4.0 in the Android flavor) 479 */ 480 @J2ktIncompatible 481 @GwtIncompatible // concurrency 482 public static boolean tryAcquireUninterruptibly( 483 Semaphore semaphore, int permits, Duration timeout) { 484 return tryAcquireUninterruptibly(semaphore, permits, toNanosSaturated(timeout), NANOSECONDS); 485 } 486 487 /** 488 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(permits, 489 * timeout, unit)} uninterruptibly. 490 * 491 * @since 18.0 492 */ 493 @J2ktIncompatible 494 @GwtIncompatible // concurrency 495 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 496 public static boolean tryAcquireUninterruptibly( 497 Semaphore semaphore, int permits, long timeout, TimeUnit unit) { 498 boolean interrupted = false; 499 try { 500 long remainingNanos = unit.toNanos(timeout); 501 long end = System.nanoTime() + remainingNanos; 502 503 while (true) { 504 try { 505 // Semaphore treats negative timeouts just like zero. 506 return semaphore.tryAcquire(permits, remainingNanos, NANOSECONDS); 507 } catch (InterruptedException e) { 508 interrupted = true; 509 remainingNanos = end - System.nanoTime(); 510 } 511 } 512 } finally { 513 if (interrupted) { 514 Thread.currentThread().interrupt(); 515 } 516 } 517 } 518 519 /** 520 * Invokes {@code lock.}{@link Lock#tryLock(long, TimeUnit) tryLock(timeout, unit)} 521 * uninterruptibly. 522 * 523 * @since 30.0 (but only since 33.4.0 in the Android flavor) 524 */ 525 @J2ktIncompatible 526 @GwtIncompatible // concurrency 527 public static boolean tryLockUninterruptibly(Lock lock, Duration timeout) { 528 return tryLockUninterruptibly(lock, toNanosSaturated(timeout), NANOSECONDS); 529 } 530 531 /** 532 * Invokes {@code lock.}{@link Lock#tryLock(long, TimeUnit) tryLock(timeout, unit)} 533 * uninterruptibly. 534 * 535 * @since 30.0 536 */ 537 @J2ktIncompatible 538 @GwtIncompatible // concurrency 539 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 540 public static boolean tryLockUninterruptibly(Lock lock, long timeout, TimeUnit unit) { 541 boolean interrupted = false; 542 try { 543 long remainingNanos = unit.toNanos(timeout); 544 long end = System.nanoTime() + remainingNanos; 545 546 while (true) { 547 try { 548 return lock.tryLock(remainingNanos, NANOSECONDS); 549 } catch (InterruptedException e) { 550 interrupted = true; 551 remainingNanos = end - System.nanoTime(); 552 } 553 } 554 } finally { 555 if (interrupted) { 556 Thread.currentThread().interrupt(); 557 } 558 } 559 } 560 561 /** 562 * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit) 563 * awaitTermination(long, TimeUnit)} uninterruptibly with no timeout. 564 * 565 * @since 30.0 566 */ 567 @J2ktIncompatible 568 @GwtIncompatible // concurrency 569 public static void awaitTerminationUninterruptibly(ExecutorService executor) { 570 // TODO(cpovirk): We could optimize this to avoid calling nanoTime() at all. 571 verify(awaitTerminationUninterruptibly(executor, Long.MAX_VALUE, NANOSECONDS)); 572 } 573 574 /** 575 * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit) 576 * awaitTermination(long, TimeUnit)} uninterruptibly. 577 * 578 * @since 30.0 (but only since 33.4.0 in the Android flavor) 579 */ 580 @J2ktIncompatible 581 @GwtIncompatible // concurrency 582 public static boolean awaitTerminationUninterruptibly( 583 ExecutorService executor, Duration timeout) { 584 return awaitTerminationUninterruptibly(executor, toNanosSaturated(timeout), NANOSECONDS); 585 } 586 587 /** 588 * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit) 589 * awaitTermination(long, TimeUnit)} uninterruptibly. 590 * 591 * @since 30.0 592 */ 593 @J2ktIncompatible 594 @GwtIncompatible // concurrency 595 @SuppressWarnings("GoodTime") 596 public static boolean awaitTerminationUninterruptibly( 597 ExecutorService executor, long timeout, TimeUnit unit) { 598 boolean interrupted = false; 599 try { 600 long remainingNanos = unit.toNanos(timeout); 601 long end = System.nanoTime() + remainingNanos; 602 603 while (true) { 604 try { 605 return executor.awaitTermination(remainingNanos, NANOSECONDS); 606 } catch (InterruptedException e) { 607 interrupted = true; 608 remainingNanos = end - System.nanoTime(); 609 } 610 } 611 } finally { 612 if (interrupted) { 613 Thread.currentThread().interrupt(); 614 } 615 } 616 } 617 618 // TODO(b/4370300): Add support for waitUninterruptibly. 619 620 private Uninterruptibles() {} 621}