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; 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) 046public final class Uninterruptibles { 047 048 // Implementation Note: As of 3-7-11, the logic for each blocking/timeout 049 // methods is identical, save for method being invoked. 050 051 /** Invokes {@code latch.}{@link CountDownLatch#await() await()} uninterruptibly. */ 052 @GwtIncompatible // concurrency 053 public static void awaitUninterruptibly(CountDownLatch latch) { 054 boolean interrupted = false; 055 try { 056 while (true) { 057 try { 058 latch.await(); 059 return; 060 } catch (InterruptedException e) { 061 interrupted = true; 062 } 063 } 064 } finally { 065 if (interrupted) { 066 Thread.currentThread().interrupt(); 067 } 068 } 069 } 070 071 /** 072 * Invokes {@code latch.}{@link CountDownLatch#await(long, TimeUnit) await(timeout, unit)} 073 * uninterruptibly. 074 */ 075 @CanIgnoreReturnValue // TODO(cpovirk): Consider being more strict. 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 public static <V> V getUninterruptibly(Future<V> future) throws ExecutionException { 197 boolean interrupted = false; 198 try { 199 while (true) { 200 try { 201 return future.get(); 202 } catch (InterruptedException e) { 203 interrupted = true; 204 } 205 } 206 } finally { 207 if (interrupted) { 208 Thread.currentThread().interrupt(); 209 } 210 } 211 } 212 213 /** 214 * Invokes {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)} uninterruptibly. 215 * 216 * <p>Similar methods: 217 * 218 * <ul> 219 * <li>To retrieve a result from a {@code Future} that is already done, use {@link 220 * Futures#getDone Futures.getDone}. 221 * <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link 222 * Futures#getChecked(Future, Class, long, TimeUnit) Futures.getChecked}. 223 * <li>To get uninterruptibility and remove checked exceptions, use {@link 224 * Futures#getUnchecked}. 225 * </ul> 226 * 227 * @throws ExecutionException if the computation threw an exception 228 * @throws CancellationException if the computation was cancelled 229 * @throws TimeoutException if the wait timed out 230 */ 231 @CanIgnoreReturnValue 232 @GwtIncompatible // TODO 233 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 234 public static <V> V getUninterruptibly(Future<V> future, long timeout, TimeUnit unit) 235 throws ExecutionException, TimeoutException { 236 boolean interrupted = false; 237 try { 238 long remainingNanos = unit.toNanos(timeout); 239 long end = System.nanoTime() + remainingNanos; 240 241 while (true) { 242 try { 243 // Future treats negative timeouts just like zero. 244 return future.get(remainingNanos, NANOSECONDS); 245 } catch (InterruptedException e) { 246 interrupted = true; 247 remainingNanos = end - System.nanoTime(); 248 } 249 } 250 } finally { 251 if (interrupted) { 252 Thread.currentThread().interrupt(); 253 } 254 } 255 } 256 257 /** Invokes {@code queue.}{@link BlockingQueue#take() take()} uninterruptibly. */ 258 @GwtIncompatible // concurrency 259 public static <E> E takeUninterruptibly(BlockingQueue<E> queue) { 260 boolean interrupted = false; 261 try { 262 while (true) { 263 try { 264 return queue.take(); 265 } catch (InterruptedException e) { 266 interrupted = true; 267 } 268 } 269 } finally { 270 if (interrupted) { 271 Thread.currentThread().interrupt(); 272 } 273 } 274 } 275 276 /** 277 * Invokes {@code queue.}{@link BlockingQueue#put(Object) put(element)} uninterruptibly. 278 * 279 * @throws ClassCastException if the class of the specified element prevents it from being added 280 * to the given queue 281 * @throws IllegalArgumentException if some property of the specified element prevents it from 282 * being added to the given queue 283 */ 284 @GwtIncompatible // concurrency 285 public static <E> void putUninterruptibly(BlockingQueue<E> queue, E element) { 286 boolean interrupted = false; 287 try { 288 while (true) { 289 try { 290 queue.put(element); 291 return; 292 } catch (InterruptedException e) { 293 interrupted = true; 294 } 295 } 296 } finally { 297 if (interrupted) { 298 Thread.currentThread().interrupt(); 299 } 300 } 301 } 302 303 // TODO(user): Support Sleeper somehow (wrapper or interface method)? 304 /** Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)} uninterruptibly. */ 305 @GwtIncompatible // concurrency 306 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 307 public static void sleepUninterruptibly(long sleepFor, TimeUnit unit) { 308 boolean interrupted = false; 309 try { 310 long remainingNanos = unit.toNanos(sleepFor); 311 long end = System.nanoTime() + remainingNanos; 312 while (true) { 313 try { 314 // TimeUnit.sleep() treats negative timeouts just like zero. 315 NANOSECONDS.sleep(remainingNanos); 316 return; 317 } catch (InterruptedException e) { 318 interrupted = true; 319 remainingNanos = end - System.nanoTime(); 320 } 321 } 322 } finally { 323 if (interrupted) { 324 Thread.currentThread().interrupt(); 325 } 326 } 327 } 328 329 /** 330 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(1, 331 * timeout, unit)} uninterruptibly. 332 * 333 * @since 18.0 334 */ 335 @GwtIncompatible // concurrency 336 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 337 public static boolean tryAcquireUninterruptibly( 338 Semaphore semaphore, long timeout, TimeUnit unit) { 339 return tryAcquireUninterruptibly(semaphore, 1, timeout, unit); 340 } 341 342 /** 343 * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(permits, 344 * timeout, unit)} uninterruptibly. 345 * 346 * @since 18.0 347 */ 348 @GwtIncompatible // concurrency 349 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 350 public static boolean tryAcquireUninterruptibly( 351 Semaphore semaphore, int permits, long timeout, TimeUnit unit) { 352 boolean interrupted = false; 353 try { 354 long remainingNanos = unit.toNanos(timeout); 355 long end = System.nanoTime() + remainingNanos; 356 357 while (true) { 358 try { 359 // Semaphore treats negative timeouts just like zero. 360 return semaphore.tryAcquire(permits, remainingNanos, NANOSECONDS); 361 } catch (InterruptedException e) { 362 interrupted = true; 363 remainingNanos = end - System.nanoTime(); 364 } 365 } 366 } finally { 367 if (interrupted) { 368 Thread.currentThread().interrupt(); 369 } 370 } 371 } 372 373 /** 374 * Invokes {@code lock.}{@link Lock#tryLock(long, TimeUnit) tryLock(timeout, unit)} 375 * uninterruptibly. 376 * 377 * @since 30.0 378 */ 379 @GwtIncompatible // concurrency 380 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 381 public static boolean tryLockUninterruptibly(Lock lock, long timeout, TimeUnit unit) { 382 boolean interrupted = false; 383 try { 384 long remainingNanos = unit.toNanos(timeout); 385 long end = System.nanoTime() + remainingNanos; 386 387 while (true) { 388 try { 389 return lock.tryLock(remainingNanos, NANOSECONDS); 390 } catch (InterruptedException e) { 391 interrupted = true; 392 remainingNanos = end - System.nanoTime(); 393 } 394 } 395 } finally { 396 if (interrupted) { 397 Thread.currentThread().interrupt(); 398 } 399 } 400 } 401 402 /** 403 * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit) 404 * awaitTermination(long, TimeUnit)} uninterruptibly with no timeout. 405 * 406 * @since 30.0 407 */ 408 @Beta 409 @GwtIncompatible // concurrency 410 public static void awaitTerminationUninterruptibly(ExecutorService executor) { 411 // TODO(cpovirk): We could optimize this to avoid calling nanoTime() at all. 412 verify(awaitTerminationUninterruptibly(executor, Long.MAX_VALUE, NANOSECONDS)); 413 } 414 415 /** 416 * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit) 417 * awaitTermination(long, TimeUnit)} uninterruptibly. 418 * 419 * @since 30.0 420 */ 421 @Beta 422 @GwtIncompatible // concurrency 423 @SuppressWarnings("GoodTime") 424 public static boolean awaitTerminationUninterruptibly( 425 ExecutorService executor, long timeout, TimeUnit unit) { 426 boolean interrupted = false; 427 try { 428 long remainingNanos = unit.toNanos(timeout); 429 long end = System.nanoTime() + remainingNanos; 430 431 while (true) { 432 try { 433 return executor.awaitTermination(remainingNanos, NANOSECONDS); 434 } catch (InterruptedException e) { 435 interrupted = true; 436 remainingNanos = end - System.nanoTime(); 437 } 438 } 439 } finally { 440 if (interrupted) { 441 Thread.currentThread().interrupt(); 442 } 443 } 444 } 445 446 // TODO(user): Add support for waitUninterruptibly. 447 448 private Uninterruptibles() {} 449}