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