001 /* 002 * Copyright (C) 2011 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package com.google.common.util.concurrent; 018 019 import static java.util.concurrent.TimeUnit.NANOSECONDS; 020 021 import com.google.common.annotations.Beta; 022 import com.google.common.base.Preconditions; 023 024 import java.util.concurrent.CountDownLatch; 025 import java.util.concurrent.ExecutionException; 026 import java.util.concurrent.Future; 027 import java.util.concurrent.TimeUnit; 028 import java.util.concurrent.TimeoutException; 029 030 /** 031 * Utilities for treating interruptible operations as uninterruptible. 032 * In all cases, if a thread is interrupted during such a call, the call 033 * continues to block until the result is available or the timeout elapses, 034 * and only then re-interrupts the thread. 035 * 036 * @author Anthony Zana 037 * @since 10.0 038 */ 039 @Beta 040 public final class Uninterruptibles { 041 042 // Implementation Note: As of 3-7-11, the logic for each blocking/timeout 043 // methods is identical, save for method being invoked. 044 045 /** 046 * Invokes {@code latch.}{@link CountDownLatch#await() await()} 047 * uninterruptibly. 048 */ 049 public static void awaitUninterruptibly(CountDownLatch latch) { 050 boolean interrupted = false; 051 try { 052 while (true) { 053 try { 054 latch.await(); 055 return; 056 } catch (InterruptedException e) { 057 interrupted = true; 058 } 059 } 060 } finally { 061 if (interrupted) { 062 Thread.currentThread().interrupt(); 063 } 064 } 065 } 066 067 /** 068 * Invokes 069 * {@code latch.}{@link CountDownLatch#await(long, TimeUnit) 070 * await(timeout, unit)} uninterruptibly. 071 */ 072 public static boolean awaitUninterruptibly(CountDownLatch latch, 073 long timeout, TimeUnit unit) { 074 boolean interrupted = false; 075 try { 076 long remainingNanos = unit.toNanos(timeout); 077 long end = System.nanoTime() + remainingNanos; 078 079 while (true) { 080 try { 081 // CountDownLatch treats negative timeouts just like zero. 082 return latch.await(remainingNanos, NANOSECONDS); 083 } catch (InterruptedException e) { 084 interrupted = true; 085 remainingNanos = end - System.nanoTime(); 086 } 087 } 088 } finally { 089 if (interrupted) { 090 Thread.currentThread().interrupt(); 091 } 092 } 093 } 094 095 /** 096 * Invokes {@code toJoin.}{@link Thread#join() join()} uninterruptibly. 097 */ 098 public static void joinUninterruptibly(Thread toJoin) { 099 boolean interrupted = false; 100 try { 101 while (true) { 102 try { 103 toJoin.join(); 104 return; 105 } catch (InterruptedException e) { 106 interrupted = true; 107 } 108 } 109 } finally { 110 if (interrupted) { 111 Thread.currentThread().interrupt(); 112 } 113 } 114 } 115 116 /** 117 * Invokes {@code future.}{@link Future#get() get()} uninterruptibly. 118 * To get uninterruptibility and remove checked exceptions, see 119 * {@link Futures#getUnchecked}. 120 * 121 * <p>If instead, you wish to treat {@link InterruptedException} uniformly 122 * with other exceptions, see {@link Futures#get(Future, Class) Futures.get} 123 * or {@link Futures#makeChecked}. 124 */ 125 public static <V> V getUninterruptibly(Future<V> future) 126 throws ExecutionException { 127 boolean interrupted = false; 128 try { 129 while (true) { 130 try { 131 return future.get(); 132 } catch (InterruptedException ignored) { 133 interrupted = true; 134 } 135 } 136 } finally { 137 if (interrupted) { 138 Thread.currentThread().interrupt(); 139 } 140 } 141 } 142 143 /** 144 * Invokes 145 * {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)} 146 * uninterruptibly. 147 * 148 * <p>If instead, you wish to treat {@link InterruptedException} uniformly 149 * with other exceptions, see {@link Futures#get(Future, Class) Futures.get} 150 * or {@link Futures#makeChecked}. 151 */ 152 public static <V> V getUninterruptibly( 153 Future<V> future, long timeout, TimeUnit unit) 154 throws ExecutionException, TimeoutException { 155 boolean interrupted = false; 156 try { 157 long remainingNanos = unit.toNanos(timeout); 158 long end = System.nanoTime() + remainingNanos; 159 160 while (true) { 161 try { 162 // Future treats negative timeouts just like zero. 163 return future.get(remainingNanos, NANOSECONDS); 164 } catch (InterruptedException e) { 165 interrupted = true; 166 remainingNanos = end - System.nanoTime(); 167 } 168 } 169 } finally { 170 if (interrupted) { 171 Thread.currentThread().interrupt(); 172 } 173 } 174 } 175 176 /** 177 * Invokes 178 * {@code unit.}{@link TimeUnit#timedJoin(Thread, long) 179 * timedJoin(toJoin, timeout)} uninterruptibly. 180 */ 181 public static void joinUninterruptibly(Thread toJoin, 182 long timeout, TimeUnit unit) { 183 Preconditions.checkNotNull(toJoin); 184 boolean interrupted = false; 185 try { 186 long remainingNanos = unit.toNanos(timeout); 187 long end = System.nanoTime() + remainingNanos; 188 while (true) { 189 try { 190 // TimeUnit.timedJoin() treats negative timeouts just like zero. 191 NANOSECONDS.timedJoin(toJoin, remainingNanos); 192 return; 193 } catch (InterruptedException e) { 194 interrupted = true; 195 remainingNanos = end - System.nanoTime(); 196 } 197 } 198 } finally { 199 if (interrupted) { 200 Thread.currentThread().interrupt(); 201 } 202 } 203 } 204 // TODO(user): Support Sleeper somehow (wrapper or interface method)? 205 /** 206 * Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)} 207 * uninterruptibly. 208 */ 209 public static void sleepUninterruptibly(long sleepFor, TimeUnit unit) { 210 boolean interrupted = false; 211 try { 212 long remainingNanos = unit.toNanos(sleepFor); 213 long end = System.nanoTime() + remainingNanos; 214 while (true) { 215 try { 216 // TimeUnit.sleep() treats negative timeouts just like zero. 217 NANOSECONDS.sleep(remainingNanos); 218 return; 219 } catch (InterruptedException e) { 220 interrupted = true; 221 remainingNanos = end - System.nanoTime(); 222 } 223 } 224 } finally { 225 if (interrupted) { 226 Thread.currentThread().interrupt(); 227 } 228 } 229 } 230 231 // TODO(user): Add support for waitUninterruptibly. 232 233 private Uninterruptibles() {} 234 }