什么是线程池,如何实现的?

线程池是池化技术的一种典型实现,所谓池化技术就是提前保存大量的资源,以备不时之需。在机器资源有限的情况下,使用池化技术可以大大的提高资源的利用率,提升性能等。

线程池,说的就是提前创建好一批线程,然后保存在线程池中,当有任务需要执行的时候,从线程池选一个线程来执行任务。

在编程领域,比较典型的池化技术有:

线程池、连接池、内存池、对象池等。

Java中线程池的继承关系如下:

在这里插入图片描述
扩展:
Executors
Executors的创建线程池的方法,创建出来的线程池都实现了ExecutorService接口。常用的方法有以下几个:

newFixedThreadPool(int Threads):创建固定数目的线程池。

newCachedThreadPool():创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果没有可用的线程,则创建一个线程并添加到池中。终止并从缓存中移除那些已有60秒钟未被使用的线程。

newSingleThreadExecutor()创建一个单线程化的Executor。

newScheduledThreadPool(int corePoolSize):创建一个支持定时周期性的任务执行的线程池,多数情况下可用来替代Timer类。

线程池的实现原理
通常,一般构造函数会反映处这个工具或这个对象的数据存储结构。
在这里插入图片描述
如果把线程池比作一个公司。公司会有正式员工处理正常业务,如果工作量大的话,会雇佣外包人员来工作。

闲时就可以释放外包人员以减少公司管理开销。一个公司因为成本关系,雇佣的人员始终是有最大数。

如果这时候还有任务处理不过来,就走需求池排任务。

acc:获取调用上下文
corePoolSize:核心线程数量,可以类比正式员工数量,常驻线程数量。
maximumPoolSize:最大的线程数量,公司最多雇佣员工数量。常驻+临时线程数量。
workQueue:多余任务等待队列,再多的人都处理不过来了,需要等着,在这个地方等。
keepAliveTime:非核心线程空闲时间,就是外包人员等了多久,如果还没有活干,解雇了。
threadFactory:创建线程的工厂,在这个地方可以统一处理创建的线程的属性。每个公司对员工要求不一样,嗯,在这里设置员工的属性。
handler:线程池拒绝策略,什么意思呢?就是当任务是在是太多,人也不够,需求池也排满了,还有任务咋办?默认是不处理,抛出异常告诉任务提交者,我这忙不过来了。

添加一个任务
接着,我们看一下线程池中比较重要的execute方法,该方法用于向线程池中添加一个任务。
在这里插入图片描述核心模块用红框标记了。

第一个红框:workerCountOf方法根据ctl的低29位,得到线程池的当前线程数,如果线程数小于corePoolSize,则执行addWorker方法创建新的线程执行任务;

第二个红框:判断线程池是否在运行,如果在,任务队列是否允许插入,插入成功再次验证线程池是否运行,如果不在运行,移除插入的任务,然后抛出拒绝策略。如果在运行,没有线程了,就启用一个线程。

第三个红框:如果添加非核心线程失败,就直接拒绝了。

流程图:
在这里插入图片描述添加worker线程

从方法execute的实现可以看出:addWorker主要负责创建新的线程并执行任务,代码如下:

在这里插入图片描述第一个红框:做是否能够添加工作线程条件过滤:
判断线程池的状态,如果线程池的状态值大于或等于SHUTDOWN,则不处理提交的任务,直接返回;

第二个红框:做自旋,更新创建线程数量:
通过参数core判断当前需要创建的线程是否为核心线程,如果core为true,且当前线程数小于corePoolSize,则跳出循环,开始创建新的线程;

有人或许会疑问retry是什么?这个是java中goto语法。只能运用在break和continue后面。

接着看后面的代码:
在这里插入图片描述第一个红框:获取线程池主锁。
线程池的工作线程通过Worker类实现,通过ReentrantLock锁保证线程安全。

第二个红框:添加线程到workers中(线程池中)。

第三个红框:启动新建的线程。

接下来,我们看看workers是什么。

在这里插入图片描述一个hashSet。所以,线程池底层的存储结构其实就是一个HashSet。

worker线程处理队列任务
在这里插入图片描述第一个红框:是否是第一次执行任务,或者从队列中可以获取到任务。

第二个红框:获取到任务后,执行任务开始前操作钩子。

第三个红框:执行任务。

第四个红框:执行任务后钩子。

这两个钩子(beforeExecute,afterExecute)允许我们自己继承线程池,做任务执行前后处理。

到这里,源码分析到此为止。

总结

所谓线程池本质就是一个HashSet。多余的任务会放在阻塞队列中。

只有当阻塞队列满了后,才会出发非核心线程的创建。所以非核心线程只是临时过来打杂的。知道空闲了,然后自己关闭了。

线程池提供了两个钩子(不饿佛热Execute,afterExecute)给我们,我们继承线程池,在执行任务前后做一些事情。

线程池原理关键技术:锁(lock,cas)、阻塞队列、HashSet(资源池)
在这里插入图片描述

  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值