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