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