- 为什么要有线程池?
为了避免系统频繁的创建和销毁线程,可以让创建的 线程进行复用。
- JDK 中 线程池类的关系
- ThreadPoolExecutor 以及线程池工作原理分析
1.ThreadPoolExecutor 参数说明:
关于 WorkQueue 的详细说明上一篇BlockingQueue
拒绝策略handler 的说明:
2.线程池工作原理源码分析:
1.1 submit 源码分析
源码的 submit 中有三个分支:
- 如果 工作线程数 < corePoolSize,调用addWorker(command, true);
- 如果 工作线程数 > corePoolSize,且 当前线程池是running 状态, 将当前任务加入到 workQueue 中。
- 如果 加入工作线程失败(队列已满),执行addWorker(command,false), 其实是新创建线程执行该任务。
1.2 addWorker 源码分析:
boolean addWorker(Runnable firstTask, boolean core)
core: 为true 表示将该线程绑定到corePoolSize, 如果为true 表示将该线程绑定到 maxiNumPoolSize
1.addWorker 对 传入的任务firstTask 进行了封装,通过Worker 来封装.可以查看 Worker 的构造函数, 有成员变量thread, 这个是通过 参数ThreadFactory 来创建的线程。
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
2.最终调用 worker.thread.start 来执行 任务, 最终会调用Worker.runWorker.
runWorker 会 执行任务的task.run()。
1.3 runWorker 分析:
-
task 的取值有两种: 从参数中传过来的,或者通过getTask 获取的。 getTask 即 从blockingQueue 中take出来的. 这就实现了循环利用线程。
-
Executors 工程类提供的不同特性的线程池:
- newFixedThreadPool: 存在的问题是 这里 使用的是无界队列,存在一个问题, 如果 并发量比较大, 很有可能 无界队列中很多未处理的任务,最终内存耗尽。
- newFixedThreadPool: 存在的问题是 这里 使用的是无界队列,存在一个问题, 如果 并发量比较大, 很有可能 无界队列中很多未处理的任务,最终内存耗尽。
-
newSingleThreadPool:
3.newCachedThreadPool 如果有大量任务提交,任务执行又没那么快,就有等量的 线程被创建。很快会耗尽系统资源
- 自定义线程池
JDK 提供的线程池都存在一些问题, 在线上不建议使用。
线程池的线程大小估计:
参考
《实战Java 高并发程序设计》