• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.common.util.concurrent;
16 
17 import static com.google.common.base.Verify.verify;
18 import static java.util.concurrent.TimeUnit.NANOSECONDS;
19 
20 import com.google.common.annotations.GwtCompatible;
21 import com.google.common.annotations.GwtIncompatible;
22 import com.google.common.annotations.J2ktIncompatible;
23 import com.google.common.base.Preconditions;
24 import com.google.errorprone.annotations.CanIgnoreReturnValue;
25 import java.util.concurrent.BlockingQueue;
26 import java.util.concurrent.CancellationException;
27 import java.util.concurrent.CountDownLatch;
28 import java.util.concurrent.ExecutionException;
29 import java.util.concurrent.ExecutorService;
30 import java.util.concurrent.Future;
31 import java.util.concurrent.Semaphore;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.TimeoutException;
34 import java.util.concurrent.locks.Condition;
35 import java.util.concurrent.locks.Lock;
36 import org.checkerframework.checker.nullness.qual.Nullable;
37 
38 /**
39  * Utilities for treating interruptible operations as uninterruptible. In all cases, if a thread is
40  * interrupted during such a call, the call continues to block until the result is available or the
41  * timeout elapses, and only then re-interrupts the thread.
42  *
43  * @author Anthony Zana
44  * @since 10.0
45  */
46 @GwtCompatible(emulated = true)
47 @ElementTypesAreNonnullByDefault
48 public final class Uninterruptibles {
49 
50   // Implementation Note: As of 3-7-11, the logic for each blocking/timeout
51   // methods is identical, save for method being invoked.
52 
53   /** Invokes {@code latch.}{@link CountDownLatch#await() await()} uninterruptibly. */
54   @J2ktIncompatible
55   @GwtIncompatible // concurrency
awaitUninterruptibly(CountDownLatch latch)56   public static void awaitUninterruptibly(CountDownLatch latch) {
57     boolean interrupted = false;
58     try {
59       while (true) {
60         try {
61           latch.await();
62           return;
63         } catch (InterruptedException e) {
64           interrupted = true;
65         }
66       }
67     } finally {
68       if (interrupted) {
69         Thread.currentThread().interrupt();
70       }
71     }
72   }
73 
74   /**
75    * Invokes {@code latch.}{@link CountDownLatch#await(long, TimeUnit) await(timeout, unit)}
76    * uninterruptibly.
77    */
78   @J2ktIncompatible
79   @GwtIncompatible // concurrency
80   @SuppressWarnings("GoodTime") // should accept a java.time.Duration
awaitUninterruptibly(CountDownLatch latch, long timeout, TimeUnit unit)81   public static boolean awaitUninterruptibly(CountDownLatch latch, long timeout, TimeUnit unit) {
82     boolean interrupted = false;
83     try {
84       long remainingNanos = unit.toNanos(timeout);
85       long end = System.nanoTime() + remainingNanos;
86 
87       while (true) {
88         try {
89           // CountDownLatch treats negative timeouts just like zero.
90           return latch.await(remainingNanos, NANOSECONDS);
91         } catch (InterruptedException e) {
92           interrupted = true;
93           remainingNanos = end - System.nanoTime();
94         }
95       }
96     } finally {
97       if (interrupted) {
98         Thread.currentThread().interrupt();
99       }
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
awaitUninterruptibly(Condition condition, long timeout, TimeUnit unit)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
joinUninterruptibly(Thread toJoin)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
joinUninterruptibly(Thread toJoin, long timeout, TimeUnit unit)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
getUninterruptibly(Future<V> future)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
getUninterruptibly( Future<V> future, long timeout, TimeUnit unit)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
takeUninterruptibly(BlockingQueue<E> queue)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
putUninterruptibly(BlockingQueue<E> queue, E element)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
sleepUninterruptibly(long sleepFor, TimeUnit unit)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
tryAcquireUninterruptibly( Semaphore semaphore, long timeout, TimeUnit unit)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
tryAcquireUninterruptibly( Semaphore semaphore, int permits, long timeout, TimeUnit unit)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
tryLockUninterruptibly(Lock lock, long timeout, TimeUnit unit)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
awaitTerminationUninterruptibly(ExecutorService executor)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")
awaitTerminationUninterruptibly( ExecutorService executor, long timeout, TimeUnit unit)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 
Uninterruptibles()464   private Uninterruptibles() {}
465 }
466