绕不开的线程池
只看ThreadPoolExecutor的英文语义就能知道这是一个与线程池有关的类。
关于线程池,搞过开发的肯定都知道,也都能或多或少讲出相关知识;尽管如此,作者在还是想要不厌其烦的给大家加深加深记忆
线程池是一种池化技术,Java中类似的池化技术有很多,
常见的有:
- 数据库连接池
- redis连接池
- http连接池
- 内存池
- 线程池
池化技术的作用:把一些能够复用的东西(比如说连接、线程)放到初始化好的池中,便于资源统一管理。
这样做的好处:
避免重复创建、销毁、调度的开销,提高性能 保证内核的充分利用,防止过分调度 自定义参数配置达到最佳的使用效果
ThreadPoolExecutor 知识点
Java中创建线程池的方法
不推荐
通过Executors类的静态方法创建如下线程池
- FixedThreadPool (固定个数)
- ScheduledThreadPool (执行周期性任务)
- WorkStealingPool (根据当前电脑CPU处理器数量生成相应线程数)
- CachedThreadPool (带缓存功能)
- SingleThreadPool (单个线程)
推荐
通过ThreadPoolExecutor创建线程池
// 给线程定义有业务含义的名称
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("thread-pool-%s").build();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
5, // 线程池核心线程数
10, // 线程池最大线程数,达到最大值后线程池不会再增加线程
1000, // 线程池中超过corePoolSize数目的空闲线程最大存活时间
TimeUnit.MILLISECONDS, // 时间单位,毫秒
new LinkedBlockingQueue<>(50), // 工作线程等待队列
threadFactory, // 自定义线程工厂
new ThreadPoolExecutor.AbortPolicy()); // 线程池满时的拒绝策略
复制代码
为什么
先来看看阿里巴巴出品的《Java开发手册》中怎么说?
再来看看源码怎么写?
以SingleThreadPool为例,其实现也是通过ThreadPoolExecutor的构造方法创建的线程池, 之所以不推荐的原因是其使用了LinkedBlockingQueue作为工作线程的等待队列,其是一种无界缓冲等待队列,该队列的默认构造器定义的长度为Integer.MAX_VALUE
FixedThreadPool同理
CachedThreadPool采用了SynchronousQueue队列,也是一种无界无缓冲等待队列,而且其最大线程数是Integer.MAX_VALUE
ScheduledThreadPool采用了DelayedWorkQueue队列,是一种无界阻塞队列,其最大线程数是Integer.MAX_VALUE
以上四种线程池都有OOM的风险
相反,在使用ThreadPoolExecutor时,我们可以指定有界/无界阻塞队列,并指定初始长度。
ThreadPoolExecutor源码分析
线程池生命周期
Tips:千万不要把线程池的状态和线程的状态弄混了。补一张网上的线程状态图
Tips:当线程调用start(),线程在JVM中不一定立即执行,有可能要等待操作系统分配资源,此时为READY状态,当线程获得资源时进入RUNNING状态,才会真正开始执行。
拒绝策略
- CallerRunsPolicy(在当前线程中执行)