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; 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) 048public final class Uninterruptibles { 049 050 // Implementation Note: As of 3-7-11, the logic for each blocking/timeout 051 // methods is identical, save for method being invoked. 052 053 /** Invokes {@code latch.}{@link CountDownLatch#await() await()} uninterruptibly. */ 054 @GwtIncompatible // concurrency 055 public static void awaitUninterruptibly(CountDownLatch latch) { 056 boolean interrupted = false; 057 try { 058 while (true) { 059 try { 060 latch.await(); 061 return; 062 } catch (InterruptedException e) { 063 interrupted = true; 064 } 065 } 066 } finally { 067 if (interrupted) { 068 Thread.currentThread().interrupt(); 069 } 070 } 071 } 072 073 /** 074 * Invokes {@code latch.}{@link CountDownLatch#await(long, TimeUnit) await(timeout, unit)} 075 * uninterruptibly. 076 * 077 * @since 28.0 078 */ 079 @CanIgnoreReturnValue // TODO(cpovirk): Consider being more strict. 080 @GwtIncompatible // concurrency 081 @Beta 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 @Beta 123 public static boolean awaitUninterruptibly(Condition condition, Duration timeout) { 124 return awaitUninterruptibly(condition, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 125 } 126 127 /** 128 * Invokes {@code condition.}{@link Condition#await(long, TimeUnit) await(timeout, unit)} 129 * uninterruptibly. 130 * 131 * @since 23.6 132 */ 133 @GwtIncompatible // concurrency 134 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 135 public static boolean awaitUninterruptibly(Condition condition, long timeout, TimeUnit unit) { 136 boolean interrupted = false; 137 try { 138 long remainingNanos = unit.toNanos(timeout); 139 long end = System.nanoTime() + remainingNanos; 140 141 while (true) { 142 try { 143 return condition.await(remainingNanos, NANOSECONDS); 144 } catch (InterruptedException e) { 145 interrupted = true; 146 remainingNanos = end - System.nanoTime(); 147 } 148 } 149 } finally { 150 if (interrupted) { 151 Thread.currentThread().interrupt(); 152 } 153 } 154 } 155 156 /** Invokes {@code toJoin.}{@link Thread#join() join()} uninterruptibly. */ 157 @GwtIncompatible // concurrency 158 public static void joinUninterruptibly(Thread toJoin) { 159 boolean interrupted = false; 160 try { 161 while (true) { 162 try { 163 toJoin.join(); 164 return; 165 } catch (InterruptedException e) { 166 interrupted = true; 167 } 168 } 169 } finally { 170 if (interrupted) { 171 Thread.currentThread().interrupt(); 172 } 173 } 174 } 175 176 /** 177 * Invokes {@code unit.}{@link TimeUnit#timedJoin(Thread, long) timedJoin(toJoin, timeout)} 178 * uninterruptibly. 179 * 180 * @since 28.0 181 */ 182 @GwtIncompatible // concurrency 183 @Beta 184 public static void joinUninterruptibly(Thread toJoin, Duration timeout) { 185 joinUninterruptibly(toJoin, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 186 } 187 188 /** 189 * Invokes {@code unit.}{@link TimeUnit#timedJoin(Thread, long) timedJoin(toJoin, timeout)} 190 * uninterruptibly. 191 */ 192 @GwtIncompatible // concurrency 193 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 194 public static void joinUninterruptibly(Thread toJoin, long timeout, TimeUnit unit) { 195 Preconditions.checkNotNull(toJoin); 196 boolean interrupted = false; 197 try { 198 long remainingNanos = unit.toNanos(timeout); 199 long end = System.nanoTime() + remainingNanos; 200 while (true) { 201 try { 202 // TimeUnit.timedJoin() treats negative timeouts just like zero. 203 NANOSECONDS.timedJoin(toJoin, remainingNanos); 204 return; 205 } catch (InterruptedException e) { 206 interrupted = true; 207 remainingNanos = end - System.nanoTime(); 208 } 209 } 210 } finally { 211 if (interrupted) { 212 Thread.currentThread().interrupt(); 213 } 214 } 215 } 216 217 /** 218 * Invokes {@code future.}{@link Future#get() get()} uninterruptibly. 219 * 220 * <p>Similar methods: 221 * 222 * <ul> 223 * <li>To retrieve a result from a {@code Future} that is already done, use {@link 224 * Futures#getDone Futures.getDone}. 225 * <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link 226 * Futures#getChecked(Future, Class) Futures.getChecked}. 227 * <li>To get uninterruptibility and remove checked exceptions, use {@link 228 * Futures#getUnchecked}. 229 * </ul> 230 * 231 * @throws ExecutionException if the computation threw an exception 232 * @throws CancellationException if the computation was cancelled 233 */ 234 @CanIgnoreReturnValue 235 public static <V> V getUninterruptibly(Future<V> future) 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 @Beta 274 public static <V> V getUninterruptibly(Future<V> future, Duration timeout) 275 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 public static <V> V getUninterruptibly(Future<V> future, long timeout, TimeUnit unit) 301 throws ExecutionException, TimeoutException { 302 boolean interrupted = false; 303 try { 304 long remainingNanos = unit.toNanos(timeout); 305 long end = System.nanoTime() + remainingNanos; 306 307 while (true) { 308 try { 309 // Future treats negative timeouts just like zero. 310 return future.get(remainingNanos, NANOSECONDS); 311 } catch (InterruptedException e) { 312 interrupted = true; 313 remainingNanos = end - System.nanoTime(); 314 } 315 } 316 } finally { 317 if (interrupted) { 318 Thread.currentThread().interrupt(); 319 } 320 } 321 } 322 323 /** Invokes {@code queue.}{@link BlockingQueue#take() take()} uninterruptibly. */ 324 @GwtIncompatible // concurrency 325 public static <E> E takeUninterruptibly(BlockingQueue<E> queue) { 326 boolean interrupted = false; 327 try { 328 while (true) { 329 try { 330 return queue.take(); 331 } catch (InterruptedException e) { 332 interrupted = true; 333 } 334 } 335 } finally { 336 if (interrupted) { 337 Thread.currentThread().interrupt(); 338 } 339 } 340 } 341 342 /** 343 * Invokes {@code queue.}{@link BlockingQueue#put(Object) put(element)} uninterruptibly. 344 * 345 * @throws ClassCastException if the class of the specified element prevents it from being added 346 * to the given queue 347 * @throws IllegalArgumentException if some property of the specified element prevents it from 348 * being added to the given queue 349 */ 350 @GwtIncompatible // concurrency 351 public static <E> void putUninterruptibly(BlockingQueue<E> queue, E element) { 352 boolean interrupted = false; 353 try { 354 while (true) { 355 try { 356 queue.put(element); 357 return; 358 } catch (InterruptedException e) { 359 interrupted = true; 360 } 361 } 362 } finally { 363 if (interrupted) { 364 Thread.currentThread().interrupt(); 365 } 366 } 367 } 368 369 // TODO(user): Support Sleeper somehow (wrapper or interface method)? 370 /** 371 * Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)} uninterruptibly. 372 * 373 * @since 28.0 374 */ 375 @GwtIncompatible // concurrency 376 @Beta 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 @Beta 415 public static boolean tryAcquireUninterruptibly(Semaphore semaphore, Duration timeout) { 416 return tryAcquireUninterruptibly(semaphore, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 417 } 418 419 /** 420 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(1, 421 * timeout, unit)} uninterruptibly. 422 * 423 * @since 18.0 424 */ 425 @GwtIncompatible // concurrency 426 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 427 public static boolean tryAcquireUninterruptibly( 428 Semaphore semaphore, long timeout, TimeUnit unit) { 429 return tryAcquireUninterruptibly(semaphore, 1, timeout, unit); 430 } 431 432 /** 433 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(permits, 434 * timeout, unit)} uninterruptibly. 435 * 436 * @since 28.0 437 */ 438 @GwtIncompatible // concurrency 439 @Beta 440 public static boolean tryAcquireUninterruptibly( 441 Semaphore semaphore, int permits, Duration timeout) { 442 return tryAcquireUninterruptibly( 443 semaphore, permits, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 444 } 445 446 /** 447 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(permits, 448 * timeout, unit)} uninterruptibly. 449 * 450 * @since 18.0 451 */ 452 @GwtIncompatible // concurrency 453 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 454 public static boolean tryAcquireUninterruptibly( 455 Semaphore semaphore, int permits, long timeout, TimeUnit unit) { 456 boolean interrupted = false; 457 try { 458 long remainingNanos = unit.toNanos(timeout); 459 long end = System.nanoTime() + remainingNanos; 460 461 while (true) { 462 try { 463 // Semaphore treats negative timeouts just like zero. 464 return semaphore.tryAcquire(permits, remainingNanos, NANOSECONDS); 465 } catch (InterruptedException e) { 466 interrupted = true; 467 remainingNanos = end - System.nanoTime(); 468 } 469 } 470 } finally { 471 if (interrupted) { 472 Thread.currentThread().interrupt(); 473 } 474 } 475 } 476 477 /** 478 * Invokes {@code lock.}{@link Lock#tryLock(long, TimeUnit) tryLock(timeout, unit)} 479 * uninterruptibly. 480 * 481 * @since 30.0 482 */ 483 @GwtIncompatible // concurrency 484 @Beta 485 public static boolean tryLockUninterruptibly(Lock lock, Duration timeout) { 486 return tryLockUninterruptibly(lock, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 487 } 488 489 /** 490 * Invokes {@code lock.}{@link Lock#tryLock(long, TimeUnit) tryLock(timeout, unit)} 491 * uninterruptibly. 492 * 493 * @since 30.0 494 */ 495 @GwtIncompatible // concurrency 496 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 497 public static boolean tryLockUninterruptibly(Lock lock, long timeout, TimeUnit unit) { 498 boolean interrupted = false; 499 try { 500 long remainingNanos = unit.toNanos(timeout); 501 long end = System.nanoTime() + remainingNanos; 502 503 while (true) { 504 try { 505 return lock.tryLock(remainingNanos, NANOSECONDS); 506 } catch (InterruptedException e) { 507 interrupted = true; 508 remainingNanos = end - System.nanoTime(); 509 } 510 } 511 } finally { 512 if (interrupted) { 513 Thread.currentThread().interrupt(); 514 } 515 } 516 } 517 518 /** 519 * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit) 520 * awaitTermination(long, TimeUnit)} uninterruptibly with no timeout. 521 * 522 * @since 30.0 523 */ 524 @Beta 525 @GwtIncompatible // concurrency 526 public static void awaitTerminationUninterruptibly(ExecutorService executor) { 527 // TODO(cpovirk): We could optimize this to avoid calling nanoTime() at all. 528 verify(awaitTerminationUninterruptibly(executor, Long.MAX_VALUE, NANOSECONDS)); 529 } 530 531 /** 532 * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit) 533 * awaitTermination(long, TimeUnit)} uninterruptibly. 534 * 535 * @since 30.0 536 */ 537 @Beta 538 @GwtIncompatible // concurrency 539 public static boolean awaitTerminationUninterruptibly( 540 ExecutorService executor, Duration timeout) { 541 return awaitTerminationUninterruptibly(executor, toNanosSaturated(timeout), NANOSECONDS); 542 } 543 544 /** 545 * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit) 546 * awaitTermination(long, TimeUnit)} uninterruptibly. 547 * 548 * @since 30.0 549 */ 550 @Beta 551 @GwtIncompatible // concurrency 552 @SuppressWarnings("GoodTime") 553 public static boolean awaitTerminationUninterruptibly( 554 ExecutorService executor, long timeout, TimeUnit unit) { 555 boolean interrupted = false; 556 try { 557 long remainingNanos = unit.toNanos(timeout); 558 long end = System.nanoTime() + remainingNanos; 559 560 while (true) { 561 try { 562 return executor.awaitTermination(remainingNanos, NANOSECONDS); 563 } catch (InterruptedException e) { 564 interrupted = true; 565 remainingNanos = end - System.nanoTime(); 566 } 567 } 568 } finally { 569 if (interrupted) { 570 Thread.currentThread().interrupt(); 571 } 572 } 573 } 574 575 // TODO(user): Add support for waitUninterruptibly. 576 577 private Uninterruptibles() {} 578}