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