• 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");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.util.concurrent;
18 
19 import static java.util.concurrent.TimeUnit.NANOSECONDS;
20 
21 import com.google.common.annotations.Beta;
22 import com.google.common.base.Preconditions;
23 
24 import java.util.concurrent.BlockingQueue;
25 import java.util.concurrent.CountDownLatch;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.Future;
28 import java.util.concurrent.TimeUnit;
29 import java.util.concurrent.TimeoutException;
30 
31 /**
32  * Utilities for treating interruptible operations as uninterruptible.
33  * In all cases, if a thread is interrupted during such a call, the call
34  * continues to block until the result is available or the timeout elapses,
35  * and only then re-interrupts the thread.
36  *
37  * @author Anthony Zana
38  * @since 10.0
39  */
40 @Beta
41 public final class Uninterruptibles {
42 
43   // Implementation Note: As of 3-7-11, the logic for each blocking/timeout
44   // methods is identical, save for method being invoked.
45 
46   /**
47    * Invokes {@code latch.}{@link CountDownLatch#await() await()}
48    * uninterruptibly.
49    */
awaitUninterruptibly(CountDownLatch latch)50   public static void awaitUninterruptibly(CountDownLatch latch) {
51     boolean interrupted = false;
52     try {
53       while (true) {
54         try {
55           latch.await();
56           return;
57         } catch (InterruptedException e) {
58           interrupted = true;
59         }
60       }
61     } finally {
62       if (interrupted) {
63         Thread.currentThread().interrupt();
64       }
65     }
66   }
67 
68   /**
69    * Invokes
70    * {@code latch.}{@link CountDownLatch#await(long, TimeUnit)
71    * await(timeout, unit)} uninterruptibly.
72    */
awaitUninterruptibly(CountDownLatch latch, long timeout, TimeUnit unit)73   public static boolean awaitUninterruptibly(CountDownLatch latch,
74       long timeout, TimeUnit unit) {
75     boolean interrupted = false;
76     try {
77       long remainingNanos = unit.toNanos(timeout);
78       long end = System.nanoTime() + remainingNanos;
79 
80       while (true) {
81         try {
82           // CountDownLatch treats negative timeouts just like zero.
83           return latch.await(remainingNanos, NANOSECONDS);
84         } catch (InterruptedException e) {
85           interrupted = true;
86           remainingNanos = end - System.nanoTime();
87         }
88       }
89     } finally {
90       if (interrupted) {
91         Thread.currentThread().interrupt();
92       }
93     }
94   }
95 
96   /**
97    * Invokes {@code toJoin.}{@link Thread#join() join()} uninterruptibly.
98    */
joinUninterruptibly(Thread toJoin)99   public static void joinUninterruptibly(Thread toJoin) {
100     boolean interrupted = false;
101     try {
102       while (true) {
103         try {
104           toJoin.join();
105           return;
106         } catch (InterruptedException e) {
107           interrupted = true;
108         }
109       }
110     } finally {
111       if (interrupted) {
112         Thread.currentThread().interrupt();
113       }
114     }
115   }
116 
117   /**
118    * Invokes {@code future.}{@link Future#get() get()} uninterruptibly.
119    * To get uninterruptibility and remove checked exceptions, see
120    * {@link Futures#getUnchecked}.
121    *
122    * <p>If instead, you wish to treat {@link InterruptedException} uniformly
123    * with other exceptions, see {@link Futures#get(Future, Class) Futures.get}
124    * or {@link Futures#makeChecked}.
125    *
126    * @throws ExecutionException if the computation threw an exception
127    * @throws CancellationException if the computation was cancelled
128    */
getUninterruptibly(Future<V> future)129   public static <V> V getUninterruptibly(Future<V> future)
130       throws ExecutionException {
131     boolean interrupted = false;
132     try {
133       while (true) {
134         try {
135           return future.get();
136         } catch (InterruptedException e) {
137           interrupted = true;
138         }
139       }
140     } finally {
141       if (interrupted) {
142         Thread.currentThread().interrupt();
143       }
144     }
145   }
146 
147   /**
148    * Invokes
149    * {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)}
150    * uninterruptibly.
151    *
152    * <p>If instead, you wish to treat {@link InterruptedException} uniformly
153    * with other exceptions, see {@link Futures#get(Future, Class) Futures.get}
154    * or {@link Futures#makeChecked}.
155    *
156    * @throws ExecutionException if the computation threw an exception
157    * @throws CancellationException if the computation was cancelled
158    * @throws TimeoutException if the wait timed out
159    */
getUninterruptibly( Future<V> future, long timeout, TimeUnit unit)160   public static <V> V getUninterruptibly(
161       Future<V> future, long timeout,  TimeUnit unit)
162           throws ExecutionException, TimeoutException {
163     boolean interrupted = false;
164     try {
165       long remainingNanos = unit.toNanos(timeout);
166       long end = System.nanoTime() + remainingNanos;
167 
168       while (true) {
169         try {
170           // Future treats negative timeouts just like zero.
171           return future.get(remainingNanos, NANOSECONDS);
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
186    * {@code unit.}{@link TimeUnit#timedJoin(Thread, long)
187    * timedJoin(toJoin, timeout)} uninterruptibly.
188    */
joinUninterruptibly(Thread toJoin, long timeout, TimeUnit unit)189   public static void joinUninterruptibly(Thread toJoin,
190       long timeout, TimeUnit unit) {
191     Preconditions.checkNotNull(toJoin);
192     boolean interrupted = false;
193     try {
194       long remainingNanos = unit.toNanos(timeout);
195       long end = System.nanoTime() + remainingNanos;
196       while (true) {
197         try {
198           // TimeUnit.timedJoin() treats negative timeouts just like zero.
199           NANOSECONDS.timedJoin(toJoin, remainingNanos);
200           return;
201         } catch (InterruptedException e) {
202           interrupted = true;
203           remainingNanos = end - System.nanoTime();
204         }
205       }
206     } finally {
207       if (interrupted) {
208         Thread.currentThread().interrupt();
209       }
210     }
211   }
212 
213   /**
214    * Invokes {@code queue.}{@link BlockingQueue#take() take()} uninterruptibly.
215    */
takeUninterruptibly(BlockingQueue<E> queue)216   public static <E> E takeUninterruptibly(BlockingQueue<E> queue) {
217     boolean interrupted = false;
218     try {
219       while (true) {
220         try {
221           return queue.take();
222         } catch (InterruptedException e) {
223           interrupted = true;
224         }
225       }
226     } finally {
227       if (interrupted) {
228         Thread.currentThread().interrupt();
229       }
230     }
231   }
232 
233   /**
234    * Invokes {@code queue.}{@link BlockingQueue#put(Object) put(element)}
235    * uninterruptibly.
236    *
237    * @throws ClassCastException if the class of the specified element prevents
238    *     it from being added to the given queue
239    * @throws IllegalArgumentException if some property of the specified element
240    *     prevents it from being added to the given queue
241    */
putUninterruptibly(BlockingQueue<E> queue, E element)242   public static <E> void putUninterruptibly(BlockingQueue<E> queue, E element) {
243     boolean interrupted = false;
244     try {
245       while (true) {
246         try {
247           queue.put(element);
248           return;
249         } catch (InterruptedException e) {
250           interrupted = true;
251         }
252       }
253     } finally {
254       if (interrupted) {
255         Thread.currentThread().interrupt();
256       }
257     }
258   }
259 
260   // TODO(user): Support Sleeper somehow (wrapper or interface method)?
261   /**
262    * Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)}
263    * uninterruptibly.
264    */
sleepUninterruptibly(long sleepFor, TimeUnit unit)265   public static void sleepUninterruptibly(long sleepFor, TimeUnit unit) {
266     boolean interrupted = false;
267     try {
268       long remainingNanos = unit.toNanos(sleepFor);
269       long end = System.nanoTime() + remainingNanos;
270       while (true) {
271         try {
272           // TimeUnit.sleep() treats negative timeouts just like zero.
273           NANOSECONDS.sleep(remainingNanos);
274           return;
275         } catch (InterruptedException e) {
276           interrupted = true;
277           remainingNanos = end - System.nanoTime();
278         }
279       }
280     } finally {
281       if (interrupted) {
282         Thread.currentThread().interrupt();
283       }
284     }
285   }
286 
287   // TODO(user): Add support for waitUninterruptibly.
288 
Uninterruptibles()289   private Uninterruptibles() {}
290 }
291