ThreadFactory 是 Java 中用于统一创建线程的接口,专注定制线程名、优先级、守护状态及未捕获异常处理器,避免手动 new Thread() 导致逻辑散乱和线程池不可控。

ThreadFactory 是 Java 并发编程中控制线程实例化过程的轻量级接口,它不负责调度或生命周期管理,只专注“**怎么 new 出一个 Thread 对象**”。如果你需要统一设置线程名、优先级、是否守护线程、未捕获异常处理器,或者做线程创建审计(比如统计线程数),就必须用它——而不是在每次 new Thread() 时重复写一堆 setXXX()。
为什么不能直接 new Thread()?
手动 new Thread() 会导致逻辑散落、难以维护,尤其在线程池场景下完全不可控。例如:
- 线程池内部创建新线程时,调用的是
ThreadFactory.newThread(Runnable),你无法干预; - 默认的
Executors.defaultThreadFactory()创建的线程名是pool-1-thread-1这类无业务含义的名字,排查问题时难定位; - 没设
setUncaughtExceptionHandler(),线程内抛出未捕获异常会静默消失,日志里找不到痕迹。
如何实现一个带命名和异常处理的 ThreadFactory
最常见需求:给每个线程加前缀、设为非守护线程、绑定统一异常处理器。注意三点:
-
ThreadFactory是函数式接口,可用 lambda,但**推荐写成静态内部类或独立类**,避免闭包持有外部对象导致内存泄漏; - 线程名必须唯一,否则 JMX 或调试工具会混淆,建议用原子计数器(
AtomicInteger); -
uncaughtExceptionHandler要在newThread()内设置,不是构造时设置——因为线程对象还没真正创建。
public class NamedThreadFactory implements ThreadFactory {
private final String prefix;
private final AtomicInteger threadNumber = new AtomicInteger(1);
public NamedThreadFactory(String prefix) {
this.prefix = prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, prefix + "-" + threadNumber.getAndIncrement());
t.setDaemon(false);
t.setPriority(Thread.NORM_PRIORITY);
t.setUncaughtExceptionHandler((thread, ex) ->
System.err.println("Uncaught in " + thread.getName() + ": " + ex));
return t;
}
}
在 ThreadPoolExecutor 和 Executors 中怎么用
所有标准线程池构造器都接受 ThreadFactory 参数,但位置不同,容易传错:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
-
ThreadPoolExecutor构造器第 5 个参数是ThreadFactory,别和第 4 个BlockingQueue搞混; -
Executors.newFixedThreadPool(int, ThreadFactory)等工厂方法有重载,**必须显式传入ThreadFactory版本**,否则还是走默认; - Spring 的
ThreadPoolTaskExecutor用setThreadFactory()方法注入,不是构造器。
示例(正确用法):
ThreadFactory factory = new NamedThreadFactory("cache-loader");
ExecutorService executor = new ThreadPoolExecutor(
2, 4,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
factory, // ← 就是这里
new ThreadPoolExecutor.CallerRunsPolicy()
);
容易被忽略的坑:线程名重复、异常处理器失效、与线程池拒绝策略交互
真实线上问题往往出在细节:
- 多个线程池共用同一个
NamedThreadFactory实例 →threadNumber共享 → 线程名重复(如io-1出现两次);解决:每个线程池配独立实例,或把前缀做到更细粒度(如"io-db"/"io-cache"); - 设置了
setUncaughtExceptionHandler,但线程池中任务抛异常后仍没打印 → 原因是Runnable被FutureTask包装,异常被捕获进Future.get(),不会触发线程级 handler;解决:要么改用Callable+ 显式get(),要么在Runnable内部 try-catch; - 自定义
ThreadFactory创建失败(比如构造线程时 OOM),线程池会直接抛RejectedExecutionException,即使队列没满——这是底层addWorker()的逻辑,不是拒绝策略触发的。
线程创建逻辑越简单越好,不要在 newThread() 里做耗时操作(如远程配置拉取、日志初始化),否则会拖慢线程池扩容节奏,甚至卡死。

















