• 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    */
getUninterruptibly(Future<V> future)126   public static <V> V getUninterruptibly(Future<V> future)
127       throws ExecutionException {
128     boolean interrupted = false;
129     try {
130       while (true) {
131         try {
132           return future.get();
133         } catch (InterruptedException e) {
134           interrupted = true;
135         }
136       }
137     } finally {
138       if (interrupted) {
139         Thread.currentThread().interrupt();
140       }
141     }
142   }
143 
144   /**
145    * Invokes
146    * {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)}
147    * uninterruptibly.
148    *
149    * <p>If instead, you wish to treat {@link InterruptedException} uniformly
150    * with other exceptions, see {@link Futures#get(Future, Class) Futures.get}
151    * or {@link Futures#makeChecked}.
152    */
getUninterruptibly( Future<V> future, long timeout, TimeUnit unit)153   public static <V> V getUninterruptibly(
154       Future<V> future, long timeout,  TimeUnit unit)
155           throws ExecutionException, TimeoutException {
156     boolean interrupted = false;
157     try {
158       long remainingNanos = unit.toNanos(timeout);
159       long end = System.nanoTime() + remainingNanos;
160 
161       while (true) {
162         try {
163           // Future treats negative timeouts just like zero.
164           return future.get(remainingNanos, NANOSECONDS);
165         } catch (InterruptedException e) {
166           interrupted = true;
167           remainingNanos = end - System.nanoTime();
168         }
169       }
170     } finally {
171       if (interrupted) {
172         Thread.currentThread().interrupt();
173       }
174     }
175   }
176 
177   /**
178    * Invokes
179    * {@code unit.}{@link TimeUnit#timedJoin(Thread, long)
180    * timedJoin(toJoin, timeout)} uninterruptibly.
181    */
joinUninterruptibly(Thread toJoin, long timeout, TimeUnit unit)182   public static void joinUninterruptibly(Thread toJoin,
183       long timeout, TimeUnit unit) {
184     Preconditions.checkNotNull(toJoin);
185     boolean interrupted = false;
186     try {
187       long remainingNanos = unit.toNanos(timeout);
188       long end = System.nanoTime() + remainingNanos;
189       while (true) {
190         try {
191           // TimeUnit.timedJoin() treats negative timeouts just like zero.
192           NANOSECONDS.timedJoin(toJoin, remainingNanos);
193           return;
194         } catch (InterruptedException e) {
195           interrupted = true;
196           remainingNanos = end - System.nanoTime();
197         }
198       }
199     } finally {
200       if (interrupted) {
201         Thread.currentThread().interrupt();
202       }
203     }
204   }
205 
206   /**
207    * Invokes {@code queue.}{@link BlockingQueue#take() take()} uninterruptibly.
208    */
takeUninterruptibly(BlockingQueue<E> queue)209   public static <E> E takeUninterruptibly(BlockingQueue<E> queue) {
210     boolean interrupted = false;
211     try {
212       while (true) {
213         try {
214           return queue.take();
215         } catch (InterruptedException e) {
216           interrupted = true;
217         }
218       }
219     } finally {
220       if (interrupted) {
221         Thread.currentThread().interrupt();
222       }
223     }
224   }
225 
226   /**
227    * Invokes {@code queue.}{@link BlockingQueue#put(Object) put(element)}
228    * uninterruptibly.
229    */
putUninterruptibly(BlockingQueue<E> queue, E element)230   public static <E> void putUninterruptibly(BlockingQueue<E> queue, E element) {
231     boolean interrupted = false;
232     try {
233       while (true) {
234         try {
235           queue.put(element);
236           return;
237         } catch (InterruptedException e) {
238           interrupted = true;
239         }
240       }
241     } finally {
242       if (interrupted) {
243         Thread.currentThread().interrupt();
244       }
245     }
246   }
247 
248   // TODO(user): Support Sleeper somehow (wrapper or interface method)?
249   /**
250    * Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)}
251    * uninterruptibly.
252    */
sleepUninterruptibly(long sleepFor, TimeUnit unit)253   public static void sleepUninterruptibly(long sleepFor, TimeUnit unit) {
254     boolean interrupted = false;
255     try {
256       long remainingNanos = unit.toNanos(sleepFor);
257       long end = System.nanoTime() + remainingNanos;
258       while (true) {
259         try {
260           // TimeUnit.sleep() treats negative timeouts just like zero.
261           NANOSECONDS.sleep(remainingNanos);
262           return;
263         } catch (InterruptedException e) {
264           interrupted = true;
265           remainingNanos = end - System.nanoTime();
266         }
267       }
268     } finally {
269       if (interrupted) {
270         Thread.currentThread().interrupt();
271       }
272     }
273   }
274 
275   // TODO(user): Add support for waitUninterruptibly.
276 
Uninterruptibles()277   private Uninterruptibles() {}
278 }
279