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