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