Home | History | Annotate | Download | only in concurrent
      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    */
     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    */
     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    */
     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   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    */
    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    */
    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    */
    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    */
    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    */
    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 
    277   private Uninterruptibles() {}
    278 }
    279