summaryrefslogtreecommitdiffstats
path: root/guava/src/com/google/common/util/concurrent/Uninterruptibles.java
diff options
context:
space:
mode:
Diffstat (limited to 'guava/src/com/google/common/util/concurrent/Uninterruptibles.java')
-rw-r--r--guava/src/com/google/common/util/concurrent/Uninterruptibles.java278
1 files changed, 278 insertions, 0 deletions
diff --git a/guava/src/com/google/common/util/concurrent/Uninterruptibles.java b/guava/src/com/google/common/util/concurrent/Uninterruptibles.java
new file mode 100644
index 0000000..89f30b8
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/Uninterruptibles.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Utilities for treating interruptible operations as uninterruptible.
+ * In all cases, if a thread is interrupted during such a call, the call
+ * continues to block until the result is available or the timeout elapses,
+ * and only then re-interrupts the thread.
+ *
+ * @author Anthony Zana
+ * @since 10.0
+ */
+@Beta
+public final class Uninterruptibles {
+
+ // Implementation Note: As of 3-7-11, the logic for each blocking/timeout
+ // methods is identical, save for method being invoked.
+
+ /**
+ * Invokes {@code latch.}{@link CountDownLatch#await() await()}
+ * uninterruptibly.
+ */
+ public static void awaitUninterruptibly(CountDownLatch latch) {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ latch.await();
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes
+ * {@code latch.}{@link CountDownLatch#await(long, TimeUnit)
+ * await(timeout, unit)} uninterruptibly.
+ */
+ public static boolean awaitUninterruptibly(CountDownLatch latch,
+ long timeout, TimeUnit unit) {
+ boolean interrupted = false;
+ try {
+ long remainingNanos = unit.toNanos(timeout);
+ long end = System.nanoTime() + remainingNanos;
+
+ while (true) {
+ try {
+ // CountDownLatch treats negative timeouts just like zero.
+ return latch.await(remainingNanos, NANOSECONDS);
+ } catch (InterruptedException e) {
+ interrupted = true;
+ remainingNanos = end - System.nanoTime();
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes {@code toJoin.}{@link Thread#join() join()} uninterruptibly.
+ */
+ public static void joinUninterruptibly(Thread toJoin) {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ toJoin.join();
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes {@code future.}{@link Future#get() get()} uninterruptibly.
+ * To get uninterruptibility and remove checked exceptions, see
+ * {@link Futures#getUnchecked}.
+ *
+ * <p>If instead, you wish to treat {@link InterruptedException} uniformly
+ * with other exceptions, see {@link Futures#get(Future, Class) Futures.get}
+ * or {@link Futures#makeChecked}.
+ */
+ public static <V> V getUninterruptibly(Future<V> future)
+ throws ExecutionException {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ return future.get();
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes
+ * {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)}
+ * uninterruptibly.
+ *
+ * <p>If instead, you wish to treat {@link InterruptedException} uniformly
+ * with other exceptions, see {@link Futures#get(Future, Class) Futures.get}
+ * or {@link Futures#makeChecked}.
+ */
+ public static <V> V getUninterruptibly(
+ Future<V> future, long timeout, TimeUnit unit)
+ throws ExecutionException, TimeoutException {
+ boolean interrupted = false;
+ try {
+ long remainingNanos = unit.toNanos(timeout);
+ long end = System.nanoTime() + remainingNanos;
+
+ while (true) {
+ try {
+ // Future treats negative timeouts just like zero.
+ return future.get(remainingNanos, NANOSECONDS);
+ } catch (InterruptedException e) {
+ interrupted = true;
+ remainingNanos = end - System.nanoTime();
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes
+ * {@code unit.}{@link TimeUnit#timedJoin(Thread, long)
+ * timedJoin(toJoin, timeout)} uninterruptibly.
+ */
+ public static void joinUninterruptibly(Thread toJoin,
+ long timeout, TimeUnit unit) {
+ Preconditions.checkNotNull(toJoin);
+ boolean interrupted = false;
+ try {
+ long remainingNanos = unit.toNanos(timeout);
+ long end = System.nanoTime() + remainingNanos;
+ while (true) {
+ try {
+ // TimeUnit.timedJoin() treats negative timeouts just like zero.
+ NANOSECONDS.timedJoin(toJoin, remainingNanos);
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ remainingNanos = end - System.nanoTime();
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes {@code queue.}{@link BlockingQueue#take() take()} uninterruptibly.
+ */
+ public static <E> E takeUninterruptibly(BlockingQueue<E> queue) {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ return queue.take();
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes {@code queue.}{@link BlockingQueue#put(Object) put(element)}
+ * uninterruptibly.
+ */
+ public static <E> void putUninterruptibly(BlockingQueue<E> queue, E element) {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ queue.put(element);
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ // TODO(user): Support Sleeper somehow (wrapper or interface method)?
+ /**
+ * Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)}
+ * uninterruptibly.
+ */
+ public static void sleepUninterruptibly(long sleepFor, TimeUnit unit) {
+ boolean interrupted = false;
+ try {
+ long remainingNanos = unit.toNanos(sleepFor);
+ long end = System.nanoTime() + remainingNanos;
+ while (true) {
+ try {
+ // TimeUnit.sleep() treats negative timeouts just like zero.
+ NANOSECONDS.sleep(remainingNanos);
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ remainingNanos = end - System.nanoTime();
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ // TODO(user): Add support for waitUninterruptibly.
+
+ private Uninterruptibles() {}
+}