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 }