一、异步调用方式分析
今天在写代码的时候,想要调用异步的操作,这里我是用的java8的流式异步调用,但是使用过程中呢,发现这个异步方式有两个方法,如下所示:
区别是一个 需要指定线程池
,一个不需要
。
-
那么指定线程池有哪些好处呢?直观的说有以下两点好处:
- 可以根据我们的服务器性能,通过池的管理更好的规划我们的线程数。
- 可以对我们使用的线程自定义名称,这里也是阿里java开发规范所提到的。
1.1 java8异步调用默认线程池方式
当然常规使用默认的也没什么问题。我们通过源码分析下使用默认线程池的过程。
public static CompletableFuture<Void> runAsync(Runnable runnable) {
return asyncRunStage(asyncPool, runnable);
}
看下这个asyncPool
是什么?
如下所示,useCommonPool如果为真,就使用ForkJoinPool.commonPool()
,否则创建一个new ThreadPerTaskExecutor()
:
private static final Executor asyncPool = useCommonPool ?
ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
复制代码
看看useCommonPool 是什么?
private static final boolean useCommonPool =
(ForkJoinPool.getCommonPoolParallelism() > 1);
/**
* 公共池的目标并行度级别
*/
public static int getCommonPoolParallelism() {
return commonParallelism;
}
最终这个并行级别并没有给出默认值
static final int commonParallelism;
复制代码
通过找到这个常量的调用,我们看看是如何进行初始化的,在ForkJoinPool中有一个静态代码块,启动时会对commonParallelism进行初始化,我们只关注最后一句话就好了,:
// Unsafe mechanics
private static final sun.misc.Unsafe U;
private static final int ABASE;
private static final int ASHIFT;
private static final long CTL;
private static final long RUNSTATE;
private static final long STEALCOUNTER;
private static final long PARKBLOCKER;
private static final long QTOP;
private static final long QLOCK;
private static final long QSCANSTATE;
private static final long QPARKER;
private static final long QCURRENTSTEAL;
private static final long QCURRENTJOIN;
static {
// initialize field offsets for CAS etc
try {
U = sun.misc.Unsafe.getUnsafe();
Class<?> k = ForkJoinPool.class;
CTL = U.objectFieldOffset
(k.getDeclaredField("ctl"));
RUNSTATE = U.objectFieldOffset
(k.getDeclaredField("runState"));
STEALCOUNTER = U.objectFieldOffset
(k.getDeclaredField("stealCounter"));