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