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