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(emulated = true) 049public final class Uninterruptibles { 050 051 // Implementation Note: As of 3-7-11, the logic for each blocking/timeout 052 // methods is identical, save for method being invoked. 053 054 /** Invokes {@code latch.}{@link CountDownLatch#await() await()} uninterruptibly. */ 055 @J2ktIncompatible 056 @GwtIncompatible // concurrency 057 public static void awaitUninterruptibly(CountDownLatch latch) { 058 boolean interrupted = false; 059 try { 060 while (true) { 061 try { 062 latch.await(); 063 return; 064 } catch (InterruptedException e) { 065 interrupted = true; 066 } 067 } 068 } finally { 069 if (interrupted) { 070 Thread.currentThread().interrupt(); 071 } 072 } 073 } 074 075 /** 076 * Invokes {@code latch.}{@link CountDownLatch#await(long, TimeUnit) await(timeout, unit)} 077 * uninterruptibly. 078 * 079 * @since 28.0 (but only since 33.4.0 in the Android flavor) 080 */ 081 @J2ktIncompatible 082 @GwtIncompatible // concurrency 083 public static boolean awaitUninterruptibly(CountDownLatch latch, Duration timeout) { 084 return awaitUninterruptibly(latch, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 085 } 086 087 /** 088 * Invokes {@code latch.}{@link CountDownLatch#await(long, TimeUnit) await(timeout, unit)} 089 * uninterruptibly. 090 */ 091 @J2ktIncompatible 092 @GwtIncompatible // concurrency 093 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 094 public static boolean awaitUninterruptibly(CountDownLatch latch, long timeout, TimeUnit unit) { 095 boolean interrupted = false; 096 try { 097 long remainingNanos = unit.toNanos(timeout); 098 long end = System.nanoTime() + remainingNanos; 099 100 while (true) { 101 try { 102 // CountDownLatch treats negative timeouts just like zero. 103 return latch.await(remainingNanos, NANOSECONDS); 104 } catch (InterruptedException e) { 105 interrupted = true; 106 remainingNanos = end - System.nanoTime(); 107 } 108 } 109 } finally { 110 if (interrupted) { 111 Thread.currentThread().interrupt(); 112 } 113 } 114 } 115 116 /** 117 * Invokes {@code condition.}{@link Condition#await(long, TimeUnit) await(timeout, unit)} 118 * uninterruptibly. 119 * 120 * @since 28.0 (but only since 33.4.0 in the Android flavor) 121 */ 122 @J2ktIncompatible 123 @GwtIncompatible // concurrency 124 public static boolean awaitUninterruptibly(Condition condition, Duration timeout) { 125 return awaitUninterruptibly(condition, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 126 } 127 128 /** 129 * Invokes {@code condition.}{@link Condition#await(long, TimeUnit) await(timeout, unit)} 130 * uninterruptibly. 131 * 132 * @since 23.6 133 */ 134 @J2ktIncompatible 135 @GwtIncompatible // concurrency 136 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 137 public static boolean awaitUninterruptibly(Condition condition, long timeout, TimeUnit unit) { 138 boolean interrupted = false; 139 try { 140 long remainingNanos = unit.toNanos(timeout); 141 long end = System.nanoTime() + remainingNanos; 142 143 while (true) { 144 try { 145 return condition.await(remainingNanos, NANOSECONDS); 146 } catch (InterruptedException e) { 147 interrupted = true; 148 remainingNanos = end - System.nanoTime(); 149 } 150 } 151 } finally { 152 if (interrupted) { 153 Thread.currentThread().interrupt(); 154 } 155 } 156 } 157 158 /** Invokes {@code toJoin.}{@link Thread#join() join()} uninterruptibly. */ 159 @J2ktIncompatible 160 @GwtIncompatible // concurrency 161 public static void joinUninterruptibly(Thread toJoin) { 162 boolean interrupted = false; 163 try { 164 while (true) { 165 try { 166 toJoin.join(); 167 return; 168 } catch (InterruptedException e) { 169 interrupted = true; 170 } 171 } 172 } finally { 173 if (interrupted) { 174 Thread.currentThread().interrupt(); 175 } 176 } 177 } 178 179 /** 180 * Invokes {@code unit.}{@link TimeUnit#timedJoin(Thread, long) timedJoin(toJoin, timeout)} 181 * uninterruptibly. 182 * 183 * @since 28.0 (but only since 33.4.0 in the Android flavor) 184 */ 185 @J2ktIncompatible 186 @GwtIncompatible // concurrency 187 public static void joinUninterruptibly(Thread toJoin, Duration timeout) { 188 joinUninterruptibly(toJoin, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 189 } 190 191 /** 192 * Invokes {@code unit.}{@link TimeUnit#timedJoin(Thread, long) timedJoin(toJoin, timeout)} 193 * uninterruptibly. 194 */ 195 @J2ktIncompatible 196 @GwtIncompatible // concurrency 197 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 198 public static void joinUninterruptibly(Thread toJoin, long timeout, TimeUnit unit) { 199 Preconditions.checkNotNull(toJoin); 200 boolean interrupted = false; 201 try { 202 long remainingNanos = unit.toNanos(timeout); 203 long end = System.nanoTime() + remainingNanos; 204 while (true) { 205 try { 206 // TimeUnit.timedJoin() treats negative timeouts just like zero. 207 NANOSECONDS.timedJoin(toJoin, remainingNanos); 208 return; 209 } catch (InterruptedException e) { 210 interrupted = true; 211 remainingNanos = end - System.nanoTime(); 212 } 213 } 214 } finally { 215 if (interrupted) { 216 Thread.currentThread().interrupt(); 217 } 218 } 219 } 220 221 /** 222 * Invokes {@code future.}{@link Future#get() get()} uninterruptibly. 223 * 224 * <p>Similar methods: 225 * 226 * <ul> 227 * <li>To retrieve a result from a {@code Future} that is already done, use {@link 228 * Futures#getDone Futures.getDone}. 229 * <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link 230 * Futures#getChecked(Future, Class) Futures.getChecked}. 231 * <li>To get uninterruptibility and remove checked exceptions, use {@link 232 * Futures#getUnchecked}. 233 * </ul> 234 * 235 * @throws ExecutionException if the computation threw an exception 236 * @throws CancellationException if the computation was cancelled 237 */ 238 @CanIgnoreReturnValue 239 @ParametricNullness 240 public static <V extends @Nullable Object> V getUninterruptibly(Future<V> future) 241 throws ExecutionException { 242 boolean interrupted = false; 243 try { 244 while (true) { 245 try { 246 return future.get(); 247 } catch (InterruptedException e) { 248 interrupted = true; 249 } 250 } 251 } finally { 252 if (interrupted) { 253 Thread.currentThread().interrupt(); 254 } 255 } 256 } 257 258 /** 259 * Invokes {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)} uninterruptibly. 260 * 261 * <p>Similar methods: 262 * 263 * <ul> 264 * <li>To retrieve a result from a {@code Future} that is already done, use {@link 265 * Futures#getDone Futures.getDone}. 266 * <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link 267 * Futures#getChecked(Future, Class, long, TimeUnit) Futures.getChecked}. 268 * <li>To get uninterruptibility and remove checked exceptions, use {@link 269 * Futures#getUnchecked}. 270 * </ul> 271 * 272 * @throws ExecutionException if the computation threw an exception 273 * @throws CancellationException if the computation was cancelled 274 * @throws TimeoutException if the wait timed out 275 * @since 28.0 (but only since 33.4.0 in the Android flavor) 276 */ 277 @CanIgnoreReturnValue 278 @J2ktIncompatible 279 @GwtIncompatible // java.time.Duration 280 @ParametricNullness 281 public static <V extends @Nullable Object> V getUninterruptibly( 282 Future<V> future, Duration timeout) throws ExecutionException, TimeoutException { 283 return getUninterruptibly(future, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 284 } 285 286 /** 287 * Invokes {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)} uninterruptibly. 288 * 289 * <p>Similar methods: 290 * 291 * <ul> 292 * <li>To retrieve a result from a {@code Future} that is already done, use {@link 293 * Futures#getDone Futures.getDone}. 294 * <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link 295 * Futures#getChecked(Future, Class, long, TimeUnit) Futures.getChecked}. 296 * <li>To get uninterruptibility and remove checked exceptions, use {@link 297 * Futures#getUnchecked}. 298 * </ul> 299 * 300 * @throws ExecutionException if the computation threw an exception 301 * @throws CancellationException if the computation was cancelled 302 * @throws TimeoutException if the wait timed out 303 */ 304 @CanIgnoreReturnValue 305 @J2ktIncompatible 306 @GwtIncompatible // TODO 307 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 308 @ParametricNullness 309 public static <V extends @Nullable Object> V getUninterruptibly( 310 Future<V> future, long timeout, TimeUnit unit) throws ExecutionException, TimeoutException { 311 boolean interrupted = false; 312 try { 313 long remainingNanos = unit.toNanos(timeout); 314 long end = System.nanoTime() + remainingNanos; 315 316 while (true) { 317 try { 318 // Future treats negative timeouts just like zero. 319 return future.get(remainingNanos, NANOSECONDS); 320 } catch (InterruptedException e) { 321 interrupted = true; 322 remainingNanos = end - System.nanoTime(); 323 } 324 } 325 } finally { 326 if (interrupted) { 327 Thread.currentThread().interrupt(); 328 } 329 } 330 } 331 332 /** Invokes {@code queue.}{@link BlockingQueue#take() take()} uninterruptibly. */ 333 @J2ktIncompatible 334 @GwtIncompatible // concurrency 335 public static <E> E takeUninterruptibly(BlockingQueue<E> queue) { 336 boolean interrupted = false; 337 try { 338 while (true) { 339 try { 340 return queue.take(); 341 } catch (InterruptedException e) { 342 interrupted = true; 343 } 344 } 345 } finally { 346 if (interrupted) { 347 Thread.currentThread().interrupt(); 348 } 349 } 350 } 351 352 /** 353 * Invokes {@code queue.}{@link BlockingQueue#put(Object) put(element)} uninterruptibly. 354 * 355 * @throws ClassCastException if the class of the specified element prevents it from being added 356 * to the given queue 357 * @throws IllegalArgumentException if some property of the specified element prevents it from 358 * being added to the given queue 359 */ 360 @J2ktIncompatible 361 @GwtIncompatible // concurrency 362 public static <E> void putUninterruptibly(BlockingQueue<E> queue, E element) { 363 boolean interrupted = false; 364 try { 365 while (true) { 366 try { 367 queue.put(element); 368 return; 369 } catch (InterruptedException e) { 370 interrupted = true; 371 } 372 } 373 } finally { 374 if (interrupted) { 375 Thread.currentThread().interrupt(); 376 } 377 } 378 } 379 380 // TODO(user): Support Sleeper somehow (wrapper or interface method)? 381 /** 382 * Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)} uninterruptibly. 383 * 384 * @since 28.0 (but only since 33.4.0 in the Android flavor) 385 */ 386 @J2ktIncompatible 387 @GwtIncompatible // concurrency 388 public static void sleepUninterruptibly(Duration sleepFor) { 389 sleepUninterruptibly(toNanosSaturated(sleepFor), TimeUnit.NANOSECONDS); 390 } 391 392 // TODO(user): Support Sleeper somehow (wrapper or interface method)? 393 /** Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)} uninterruptibly. */ 394 @J2ktIncompatible 395 @GwtIncompatible // concurrency 396 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 397 public static void sleepUninterruptibly(long sleepFor, TimeUnit unit) { 398 boolean interrupted = false; 399 try { 400 long remainingNanos = unit.toNanos(sleepFor); 401 long end = System.nanoTime() + remainingNanos; 402 while (true) { 403 try { 404 // TimeUnit.sleep() treats negative timeouts just like zero. 405 NANOSECONDS.sleep(remainingNanos); 406 return; 407 } catch (InterruptedException e) { 408 interrupted = true; 409 remainingNanos = end - System.nanoTime(); 410 } 411 } 412 } finally { 413 if (interrupted) { 414 Thread.currentThread().interrupt(); 415 } 416 } 417 } 418 419 /** 420 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(1, 421 * timeout, unit)} uninterruptibly. 422 * 423 * @since 28.0 (but only since 33.4.0 in the Android flavor) 424 */ 425 @J2ktIncompatible 426 @GwtIncompatible // concurrency 427 public static boolean tryAcquireUninterruptibly(Semaphore semaphore, Duration timeout) { 428 return tryAcquireUninterruptibly(semaphore, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 429 } 430 431 /** 432 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(1, 433 * timeout, unit)} uninterruptibly. 434 * 435 * @since 18.0 436 */ 437 @J2ktIncompatible 438 @GwtIncompatible // concurrency 439 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 440 public static boolean tryAcquireUninterruptibly( 441 Semaphore semaphore, long timeout, TimeUnit unit) { 442 return tryAcquireUninterruptibly(semaphore, 1, timeout, unit); 443 } 444 445 /** 446 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(permits, 447 * timeout, unit)} uninterruptibly. 448 * 449 * @since 28.0 (but only since 33.4.0 in the Android flavor) 450 */ 451 @J2ktIncompatible 452 @GwtIncompatible // concurrency 453 public static boolean tryAcquireUninterruptibly( 454 Semaphore semaphore, int permits, Duration timeout) { 455 return tryAcquireUninterruptibly( 456 semaphore, permits, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 457 } 458 459 /** 460 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(permits, 461 * timeout, unit)} uninterruptibly. 462 * 463 * @since 18.0 464 */ 465 @J2ktIncompatible 466 @GwtIncompatible // concurrency 467 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 468 public static boolean tryAcquireUninterruptibly( 469 Semaphore semaphore, int permits, long timeout, TimeUnit unit) { 470 boolean interrupted = false; 471 try { 472 long remainingNanos = unit.toNanos(timeout); 473 long end = System.nanoTime() + remainingNanos; 474 475 while (true) { 476 try { 477 // Semaphore treats negative timeouts just like zero. 478 return semaphore.tryAcquire(permits, remainingNanos, NANOSECONDS); 479 } catch (InterruptedException e) { 480 interrupted = true; 481 remainingNanos = end - System.nanoTime(); 482 } 483 } 484 } finally { 485 if (interrupted) { 486 Thread.currentThread().interrupt(); 487 } 488 } 489 } 490 491 /** 492 * Invokes {@code lock.}{@link Lock#tryLock(long, TimeUnit) tryLock(timeout, unit)} 493 * uninterruptibly. 494 * 495 * @since 30.0 (but only since 33.4.0 in the Android flavor) 496 */ 497 @J2ktIncompatible 498 @GwtIncompatible // concurrency 499 public static boolean tryLockUninterruptibly(Lock lock, Duration timeout) { 500 return tryLockUninterruptibly(lock, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 501 } 502 503 /** 504 * Invokes {@code lock.}{@link Lock#tryLock(long, TimeUnit) tryLock(timeout, unit)} 505 * uninterruptibly. 506 * 507 * @since 30.0 508 */ 509 @J2ktIncompatible 510 @GwtIncompatible // concurrency 511 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 512 public static boolean tryLockUninterruptibly(Lock lock, long timeout, TimeUnit unit) { 513 boolean interrupted = false; 514 try { 515 long remainingNanos = unit.toNanos(timeout); 516 long end = System.nanoTime() + remainingNanos; 517 518 while (true) { 519 try { 520 return lock.tryLock(remainingNanos, NANOSECONDS); 521 } catch (InterruptedException e) { 522 interrupted = true; 523 remainingNanos = end - System.nanoTime(); 524 } 525 } 526 } finally { 527 if (interrupted) { 528 Thread.currentThread().interrupt(); 529 } 530 } 531 } 532 533 /** 534 * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit) 535 * awaitTermination(long, TimeUnit)} uninterruptibly with no timeout. 536 * 537 * @since 30.0 538 */ 539 @J2ktIncompatible 540 @GwtIncompatible // concurrency 541 public static void awaitTerminationUninterruptibly(ExecutorService executor) { 542 // TODO(cpovirk): We could optimize this to avoid calling nanoTime() at all. 543 verify(awaitTerminationUninterruptibly(executor, Long.MAX_VALUE, NANOSECONDS)); 544 } 545 546 /** 547 * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit) 548 * awaitTermination(long, TimeUnit)} uninterruptibly. 549 * 550 * @since 30.0 (but only since 33.4.0 in the Android flavor) 551 */ 552 @J2ktIncompatible 553 @GwtIncompatible // concurrency 554 public static boolean awaitTerminationUninterruptibly( 555 ExecutorService executor, Duration timeout) { 556 return awaitTerminationUninterruptibly(executor, toNanosSaturated(timeout), NANOSECONDS); 557 } 558 559 /** 560 * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit) 561 * awaitTermination(long, TimeUnit)} uninterruptibly. 562 * 563 * @since 30.0 564 */ 565 @J2ktIncompatible 566 @GwtIncompatible // concurrency 567 @SuppressWarnings("GoodTime") 568 public static boolean awaitTerminationUninterruptibly( 569 ExecutorService executor, long timeout, TimeUnit unit) { 570 boolean interrupted = false; 571 try { 572 long remainingNanos = unit.toNanos(timeout); 573 long end = System.nanoTime() + remainingNanos; 574 575 while (true) { 576 try { 577 return executor.awaitTermination(remainingNanos, NANOSECONDS); 578 } catch (InterruptedException e) { 579 interrupted = true; 580 remainingNanos = end - System.nanoTime(); 581 } 582 } 583 } finally { 584 if (interrupted) { 585 Thread.currentThread().interrupt(); 586 } 587 } 588 } 589 590 // TODO(user): Add support for waitUninterruptibly. 591 592 private Uninterruptibles() {} 593}