guava 是谷歌官方一个著名的 Java 类库,增加了很多 feature ,很多都被官方借鉴。我在使用 guava 提供的 future 的时候,发现了 MoreExecutor#directExecutor
这个方法。对这个方法的理解产生了一些疑问。
场景是这样的,我们在使用 SettableFuture/ListenableFuture
的时候,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
public class FutureExample { public static void main(String[] args) { ExecutorService executor = Executors.newSingleThreadExecutor(); SettableFuture<Integer> future0 = SettableFuture.create(); executor.submit(() -> { future0.set(1); });
Futures.addCallback(future0, new FutureCallback<>() { @Override public void onSuccess(Integer result) { System.out.println("result=" + result); }
@Override public void onFailure(Throwable t) { } }, MoreExecutors.directExecutor()); } }
|
执行 callback 的线程池我们这里指定为 MoreExecutors#directExecutor
,那么这里执行打印 result 的线程到底是哪个线程呢?
可以看到是主线程。
关于 MoreExecutors#directExecutor
,可以看到定义是这样的:
1 2 3 4 5 6
| public final class MoreExecutors { public static Executor directExecutor() { return DirectExecutor.INSTANCE; } }
|
以及
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @GwtCompatible @ElementTypesAreNonnullByDefault enum DirectExecutor implements Executor { INSTANCE;
@Override public void execute(Runnable command) { command.run(); }
@Override public String toString() { return "MoreExecutors.directExecutor()"; } }
|
MoreExecutors#directExecutor
其实是一个假的线程池,表示直接执行。
那么是由谁直接执行呢?在最上面的例子中可以看到是由主线程直接执行的,那么再看下面这个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
public class FutureExample { public static void main(String[] args) { ExecutorService executor = Executors.newSingleThreadExecutor(); SettableFuture<Integer> future0 = SettableFuture.create(); executor.submit(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } future0.set(1); });
Futures.addCallback(future0, new FutureCallback<>() { @Override public void onSuccess(Integer result) { System.out.println("result=" + result); }
@Override public void onFailure(Throwable t) { } }, MoreExecutors.directExecutor()); } }
|
再看是谁执行的:
换成上面指定的线程池,那么这里清晰了:
- 如果 future 已经完成,那么
MoreExecutor#directExecutor
表示当前线程;
- 如果 future 未完成,那么
MoreExecutor#directExecutor
就是未来完成 future 的线程。
因此其实具体执行回调的线程某种程度上是不确定的。
在较低版本的 guava 中,像 Futures#addCallback
这类函数是可以不用指线程池的,当然默认行为就是使用 MoreExecutors#directExecutor
。高版本的 guava 已经去掉不带线程池的接口了,更加突出线程池在这里的地位,也就是希望开发者更加明确这里的线程池的使用,MoreExectors#directExecutor
某种程度上是模糊的。