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