文章目录
- 前言
- [ForkJoinPool.commonPool() 实现](#ForkJoinPool.commonPool() 实现)
-
- 代码整体含义
- 分步解析
-
- [1. `java.security.AccessController.doPrivileged()`](#1.
java.security.AccessController.doPrivileged()) - [2. `new java.security.PrivilegedAction<ForkJoinPool>()`](#2.
new java.security.PrivilegedAction<ForkJoinPool>()) - [3. `makeCommonPool()` 方法](#3.
makeCommonPool()方法)
- [1. `java.security.AccessController.doPrivileged()`](#1.
- 为什么要这样设计?
- 完整的初始化流程
- [makeCommonPool() 二次深入跟进](#makeCommonPool() 二次深入跟进)
- 资料获取

前言
博主介绍:✌目前全网粉丝4W+,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领域。
涵盖技术内容:Java后端、大数据、算法、分布式微服务、中间件、前端、运维等。
博主所有博客文件目录索引:博客目录索引(持续更新)
CSDN搜索:长路
视频平台:b站-Coder长路
ForkJoinPool.commonPool() 实现
代码整体含义
这段代码的目的是:以特权权限安全地创建 ForkJoinPool 公共池。
分步解析
1. java.security.AccessController.doPrivileged()
这是Java安全框架的核心方法:
- 作用:让一段代码以"特权"方式执行,暂时提升调用代码的权限
- 为什么需要 :因为创建线程池可能需要某些系统权限,而调用
ForkJoinPool.commonPool()的代码可能没有这些权限
2. new java.security.PrivilegedAction<ForkJoinPool>()
这是一个接口,定义了一个需要特权执行的操作:
java
public interface PrivilegedAction<T> {
T run();
}
3. makeCommonPool() 方法
这是实际创建公共池的核心方法,它负责:
- 读取系统属性(如
java.util.concurrent.ForkJoinPool.common.parallelism) - 创建线程工厂
- 设置异常处理器
- 最终实例化
ForkJoinPool
为什么要这样设计?
安全原因
假设有这样的调用链:
plain
你的业务代码
→ CompletableFuture.supplyAsync()
→ ForkJoinPool.commonPool()
→ 需要创建线程(需要系统权限)
如果没有 doPrivileged:
- JVM 会检查整个调用链上所有代码的权限
- 如果你的业务代码没有创建线程的权限,即使
ForkJoinPool在核心库中,也会失败
使用 doPrivileged 后:
- 在
makeCommonPool()执行时,JVM 只检查ForkJoinPool类的权限 - 忽略调用链上其他代码的权限检查
- 因为核心库是可信的,所以操作可以成功
实际场景示例
java
// 在安全限制环境下(如Applet或某些容器中)
public void myMethod() {
// 你的代码可能没有创建线程的权限
CompletableFuture.supplyAsync(() -> {
// 这个任务仍然能在公共池中执行
return expensiveCalculation();
});
}
完整的初始化流程
在 ForkJoinPool 类中,公共池的初始化大致如下:
java
public class ForkJoinPool {
// 静态常量,保存公共池实例
static final ForkJoinPool common;
static {
// 使用特权操作创建公共池
common = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<ForkJoinPool>() {
public ForkJoinPool run() {
return makeCommonPool();
}
});
}
private static ForkJoinPool makeCommonPool() {
// 1. 确定并行度(CPU核心数-1,或系统属性设置)
int parallelism = ...;
// 2. 创建线程工厂
ForkJoinWorkerThreadFactory factory = ...;
// 3. 创建异常处理器
Thread.UncaughtExceptionHandler handler = ...;
// 4. 实例化 ForkJoinPool
return new ForkJoinPool(parallelism, factory, handler, ...);
}
}
makeCommonPool() 二次深入跟进
源码
核心源码:
java
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 = new DefaultCommonPoolForkJoinWorkerThreadFactory();
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-");
}
核心细节
核心线程数 vs 最大线程数
java
// ForkJoinPool 的构造参数
public ForkJoinPool(int parallelism,
ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler,
boolean asyncMode,
String workerThreadNamePrefix) {
// parallelism 既是核心数也是最大数
this(checkParallelism(parallelism),
checkFactory(factory),
handler,
asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
workerThreadNamePrefix);
}
关键特点:
- 固定线程数 :
parallelism参数既是核心线程数也是最大线程数 - 无动态扩展:与传统线程池不同,ForkJoinPool 不动态创建/销毁线程
- 工作窃取:通过工作窃取算法提高利用率,而非增加线程数
线程数量计算逻辑:
java
// 在 common pool 中的计算
int availableProcessors = Runtime.getRuntime().availableProcessors();
int parallelism = availableProcessors - 1; // 默认:CPU核心数-1
if (parallelism <= 0) parallelism = 1; // 单核环境保证至少1个线程
拒绝策略
java
// ForkJoinPool 没有显式的拒绝策略接口
// 而是通过以下机制处理任务饱和情况:
// 1. 外部提交的任务进入提交队列
public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
if (task == null) throw new NullPointerException();
externalPush(task); // 外部提交
return task;
}
// 2. 内部生成的任务通过 fork() 进入工作队列
public final ForkJoinTask<V> fork() {
Thread t;
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
((ForkJoinWorkerThread)t).workQueue.push(this); // 内部fork
else
ForkJoinPool.common.externalPush(this); // 外部线程fork
return this;
}
实际拒绝场景:
java
// 当线程池已关闭时提交任务
if (runState < 0) { // 池已关闭
throw new RejectedExecutionException();
}
// 当系统资源耗尽时
try {
// 尝试创建新线程...
} catch (OutOfMemoryError oom) {
// 资源耗尽,无法创建线程
throw new RejectedExecutionException("Unable to create new thread", oom);
}
任务队列机制
工作窃取队列(Work-Stealing Queue):
java
// 每个工作线程都有自己的双端队列
static final class WorkQueue {
volatile int base; // 队尾指针(窃取端)
int top; // 队首指针(所有者端)
ForkJoinTask<?>[] array; // 任务数组
final ForkJoinWorkerThread owner; // 所属线程
}
LIFO vs FIFO 模式:
java
// 在 makeCommonPool() 中使用的 LIFO_QUEUE
return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
"ForkJoinPool.commonPool-worker-");
工作窃取核心逻辑:
java
// 工作线程的核心循环
final void runWorker(WorkQueue w) {
w.growArray(); // 初始化队列
for (ForkJoinTask<?> t;;) {
if ((t = w.nextLocalTask()) != null || // 1. 先处理自己的任务
(t = scan(w)) != null) // 2. 尝试窃取其他队列的任务
t.doExec(); // 执行任务
else if (tryTerminate(false, false)) // 3. 检查终止条件
break;
}
}
// 扫描其他队列窃取任务
private ForkJoinTask<?> scan(WorkQueue w) {
WorkQueue[] ws; int n;
if ((ws = workQueues) != null && (n = ws.length) > 0 && w != null) {
for (int r = w.seed, k = r, m = n - 1;;) {
WorkQueue q; int b;
if ((q = ws[k & m]) != null && (b = q.base) - q.top < 0) {
ForkJoinTask<?> t = q.pollAt(b); // 从队尾窃取
if (t != null)
return t;
}
// 继续扫描下一个队列...
}
}
return null;
}
总结
ForkJoinPool 在处理大量可分解的并行任务时(如递归计算、流处理)具有极高的性能,但在处理大量独立短期任务时可能不如传统的 ThreadPoolExecutor 高效。
具有下面特点:
- 固定线程池:线程数量固定,无动态扩展
- 工作窃取:通过窃取算法实现负载均衡,而非增加线程
- 双端队列:LIFO处理自己的任务,FIFO供其他线程窃取
- 无显式拒绝:通过队列机制和资源限制隐式处理拒绝
- 递归分解:专为可分治任务设计,支持任务拆分和结果合并
资料获取
大家点赞、收藏、关注、评论啦~
精彩专栏推荐订阅:在下方专栏👇🏻
- 长路-文章目录汇总(算法、后端Java、前端、运维技术导航):博主所有博客导航索引汇总
- 开源项目Studio-Vue---校园工作室管理系统(含前后台,SpringBoot+Vue):博主个人独立项目,包含详细部署上线视频,已开源
- 学习与生活-专栏:可以了解博主的学习历程
- 算法专栏:算法收录
更多博客与资料可查看👇🏻获取联系方式👇🏻,🍅文末获取开发资源及更多资源博客获取🍅