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