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