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