ForkJoinPool 的 commonParallelism 参数

5,152 阅读2分钟

经常看到有的框架里用ForkJoinPool.getCommonPoolParallelism(),此次又碰见了,干脆研究一下。

源码:

public class ForkJoinPool extends AbstractExecutorService {
...
   static final int commonParallelism;

   public static int getCommonPoolParallelism() {
        return commonParallelism;
   }
...
}

ForkJoinPool.getCommonPoolParallelism()返回的是commonParallelism的值,所以只需要研究在哪里对commonParallelism进行了赋值。源码如下:

...
static final ForkJoinPool common;
static {
    ...
    common = java.security.AccessController.doPrivileged
      (new java.security.PrivilegedAction<ForkJoinPool>() {
          public ForkJoinPool run() {
            return makeCommonPool(); //common的config由此方法返回
          }});
    int par = common.config & SMASK; // report 1 even if threads disabled
    commonParallelism = par > 0 ? par : 1;
}

commonParallelism的值跟par有关, par最终又来源于ForkJoinPool的makeCommonPool()方法,其源码如下:

private static ForkJoinPool makeCommonPool() {
    int parallelism = -1;
    ForkJoinWorkerThreadFactory factory = null;
    UncaughtExceptionHandler handler = null;
    try {  // ignore exceptions in accessing/parsing properties
        String pp = System.getProperty
            ("java.util.concurrent.ForkJoinPool.common.parallelism");
        String fp = System.getProperty
            ("java.util.concurrent.ForkJoinPool.common.threadFactory");
        String hp = System.getProperty
            ("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
        if (pp != null)
            parallelism = Integer.parseInt(pp);
        if (fp != null)
            factory = ((ForkJoinWorkerThreadFactory)ClassLoader.
                       getSystemClassLoader().loadClass(fp).newInstance());
        if (hp != null)
            handler = ((UncaughtExceptionHandler)ClassLoader.
                       getSystemClassLoader().loadClass(hp).newInstance());
    } catch (Exception ignore) {
    }
    if (factory == null) {
        if (System.getSecurityManager() == null)
            factory = defaultForkJoinWorkerThreadFactory;
        else // use security-managed default
            factory = new InnocuousForkJoinWorkerThreadFactory();
    }
    if (parallelism < 0 && // default 1 less than #cores
        (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
        parallelism = 1;
    if (parallelism > MAX_CAP)
        parallelism = MAX_CAP;
    return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
                            "ForkJoinPool.commonPool-worker-");
}
...
private ForkJoinPool(int parallelism,
                     ForkJoinWorkerThreadFactory factory,
                     UncaughtExceptionHandler handler,
                     int mode,
                     String workerNamePrefix) {
    this.workerNamePrefix = workerNamePrefix;
    this.factory = factory;
    this.ueh = handler;
    this.config = (parallelism & SMASK) | mode;
    long np = (long)(-parallelism); // offset ctl counts
    this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
}

分析makeCommonPool方法可知,其并行度parallelism由jvm启动参数java.util.concurrent.ForkJoinPool.common.parallelism来指定,然后对其进行校验,若parallelism<=0,且机器逻辑核心数-1后小于等于0,则赋值为1,若parallelism>MAX_CAP, 赋值为MAX_CAP(MAX_CAP=32767)。然后parallelism与SMASK(SMASK=65535)做与运算的结果再与mode(mode=0)做或运算【什么意思呢,就是parallelism最大不能超过65535,如果parallelism=0那么就返回0】。 然后config的值再与SMASK做与运算就是返回的最终值。

总结: ForkJoinPool.getCommonPoolParallelism()如果jvm启动参数配置了且有效(大于1小于32767),则返回的配置的值。如果没有配置又分两种情况,一机器逻辑核心数<=1,返回1;二机器逻辑核心数>1则返回(机器逻辑核心数-1)。