001 /*
002 * Copyright (C) 2009 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 com.google.common.base.Preconditions.checkNotNull;
020
021 import com.google.common.annotations.Beta;
022
023 import java.util.concurrent.Executor;
024 import java.util.concurrent.Executors;
025 import java.util.concurrent.Future;
026 import java.util.concurrent.ThreadFactory;
027 import java.util.concurrent.atomic.AtomicBoolean;
028
029 /**
030 * Utilities necessary for working with libraries that supply plain {@link
031 * Future} instances. Note that, whenver possible, it is strongly preferred to
032 * modify those libraries to return {@code ListenableFuture} directly.
033 *
034 * @author Sven Mawson
035 * @since 10.0 (replacing {@code Futures.makeListenable}, which
036 * existed in 1.0)
037 */
038 @Beta
039 public final class JdkFutureAdapters {
040 /**
041 * Assigns a thread to the given {@link Future} to provide {@link
042 * ListenableFuture} functionality.
043 *
044 * <p><b>Warning:</b> If the input future does not already implement {@code
045 * ListenableFuture}, the returned future will emulate {@link
046 * ListenableFuture#addListener} by taking a thread from an internal,
047 * unbounded pool at the first call to {@code addListener} and holding it
048 * until the future is {@linkplain Future#isDone() done}.
049 *
050 * <p>Prefer to create {@code ListenableFuture} instances with {@link
051 * SettableFuture}, {@link MoreExecutors#listeningDecorator(
052 * java.util.concurrent.ExecutorService)}, {@link ListenableFutureTask},
053 * {@link AbstractFuture}, and other utilities over creating plain {@code
054 * Future} instances to be upgraded to {@code ListenableFuture} after the
055 * fact.
056 */
057 public static <V> ListenableFuture<V> listenInPoolThread(
058 Future<V> future) {
059 if (future instanceof ListenableFuture) {
060 return (ListenableFuture<V>) future;
061 }
062 return new ListenableFutureAdapter<V>(future);
063 }
064
065 /**
066 * Submits a blocking task for the given {@link Future} to provide {@link
067 * ListenableFuture} functionality.
068 *
069 * <p><b>Warning:</b> If the input future does not already implement {@code
070 * ListenableFuture}, the returned future will emulate {@link
071 * ListenableFuture#addListener} by submitting a task to the given executor at
072 * at the first call to {@code addListener}. The task must be started by the
073 * executor promptly, or else the returned {@code ListenableFuture} may fail
074 * to work. The task's execution consists of blocking until the input future
075 * is {@linkplain Future#isDone() done}, so each call to this method may
076 * claim and hold a thread for an arbitrary length of time. Use of bounded
077 * executors or other executors that may fail to execute a task promptly may
078 * result in deadlocks.
079 *
080 * <p>Prefer to create {@code ListenableFuture} instances with {@link
081 * SettableFuture}, {@link MoreExecutors#listeningDecorator(
082 * java.util.concurrent.ExecutorService)}, {@link ListenableFutureTask},
083 * {@link AbstractFuture}, and other utilities over creating plain {@code
084 * Future} instances to be upgraded to {@code ListenableFuture} after the
085 * fact.
086 *
087 * @since 12.0
088 */
089 public static <V> ListenableFuture<V> listenInPoolThread(
090 Future<V> future, Executor executor) {
091 checkNotNull(executor);
092 if (future instanceof ListenableFuture) {
093 return (ListenableFuture<V>) future;
094 }
095 return new ListenableFutureAdapter<V>(future, executor);
096 }
097
098 /**
099 * An adapter to turn a {@link Future} into a {@link ListenableFuture}. This
100 * will wait on the future to finish, and when it completes, run the
101 * listeners. This implementation will wait on the source future
102 * indefinitely, so if the source future never completes, the adapter will
103 * never complete either.
104 *
105 * <p>If the delegate future is interrupted or throws an unexpected unchecked
106 * exception, the listeners will not be invoked.
107 */
108 private static class ListenableFutureAdapter<V> extends ForwardingFuture<V>
109 implements ListenableFuture<V> {
110
111 private static final ThreadFactory threadFactory =
112 new ThreadFactoryBuilder()
113 .setDaemon(true)
114 .setNameFormat("ListenableFutureAdapter-thread-%d")
115 .build();
116 private static final Executor defaultAdapterExecutor =
117 Executors.newCachedThreadPool(threadFactory);
118
119 private final Executor adapterExecutor;
120
121 // The execution list to hold our listeners.
122 private final ExecutionList executionList = new ExecutionList();
123
124 // This allows us to only start up a thread waiting on the delegate future
125 // when the first listener is added.
126 private final AtomicBoolean hasListeners = new AtomicBoolean(false);
127
128 // The delegate future.
129 private final Future<V> delegate;
130
131 ListenableFutureAdapter(Future<V> delegate) {
132 this(delegate, defaultAdapterExecutor);
133 }
134
135 ListenableFutureAdapter(Future<V> delegate, Executor adapterExecutor) {
136 this.delegate = checkNotNull(delegate);
137 this.adapterExecutor = checkNotNull(adapterExecutor);
138 }
139
140 @Override
141 protected Future<V> delegate() {
142 return delegate;
143 }
144
145 @Override
146 public void addListener(Runnable listener, Executor exec) {
147 executionList.add(listener, exec);
148
149 // When a listener is first added, we run a task that will wait for
150 // the delegate to finish, and when it is done will run the listeners.
151 if (hasListeners.compareAndSet(false, true)) {
152 if (delegate.isDone()) {
153 // If the delegate is already done, run the execution list
154 // immediately on the current thread.
155 executionList.execute();
156 return;
157 }
158
159 adapterExecutor.execute(new Runnable() {
160 @Override
161 public void run() {
162 try {
163 delegate.get();
164 } catch (Error e) {
165 throw e;
166 } catch (InterruptedException e) {
167 Thread.currentThread().interrupt();
168 // Threads from our private pool are never interrupted.
169 throw new AssertionError(e);
170 } catch (Throwable e) {
171 // ExecutionException / CancellationException / RuntimeException
172 // The task is done, run the listeners.
173 }
174 executionList.execute();
175 }
176 });
177 }
178 }
179 }
180
181 private JdkFutureAdapters() {}
182 }