java线程池原理_面试必问:java线程池实现原理

处理器早已迈入多核心时代,为了充分利用cpu多核资源,应用都会采用多线程并行/并发计算,最大限度的利用多核提升应用程序性能。然而线程的创建是有代价的,一方面需要申请内存资源,另一方面需要操作系统内核把线程加入调度队列,开销是比较大的,这在高并发系统中性能隐患非常大,另一方面线程需要消耗内存空间,如果进程创建的线程数量不加以控制,很有可能会耗尽进程的内存空间。

为了解决多线程的上面两个问题,前辈们设计出了线程池,线程池有两个主要作用:

1、不同请求之间重复利用线程,无需频繁的创建和销毁线程,降低系统开销;

2、控制线程数量上限,避免创建过多的线程耗尽进程内存空间,同时减少线程上下文切换次数。

jdk在java5版本中增加了内置线程池实现ThreadPoolExecutor,本文通过ThreadPoolExecutor的源码分析jdk中线程池的实现原理。

线程池由两个核心数据结构组成:

1)线程集合(workers):存放执行任务的线程,是一个HashSet;

2)任务等待队列(workQueue):存放等待线程池调度执行的任务,是一个阻塞式队列BlockingQueue;

e38fe51c6687fb3239a069b3a36d0a00.png

线程池有几个核心参数:

416c504dd9dafb25bc2739b324b50dbd.png

任务执行流程

任务由execute方法提交到线程池中调度,在提交任务时会有下面几种场景:

1)线程池中线程数量小于corePoolSize,此时任务不会进等待队列,线程池直接创建一个线程Worker执行提交的任务;

a89c32b9507d7d512ae94e370dc066a5.png

2)线程池中线程数量不小于corePoolSize并且等待队列未满,任务直接添加到等待队列,等待线程池调度执行;

7d92af08b2230b85bc01a3cedf10de7f.png

3)线程池中线程数量不小于corePoolSize但是等待队列已满且线程数量小于maximumPoolSize,线程池会进行扩容新创建一个线程Worker执行提交的任务,新创建的Worker会被添加到线程集合workers中;

aabbd05cab7b35c01a12a309e1e6ed98.png

4)等待队列已满并且线程数量已达到maximumPoolSize,这种情况下线程池无法继续执行任务会拒绝任务,执行一个指定的拒接策略。

642423851933400327ece452be4c4ca4.png

5)线程池已关闭,拒绝任务,执行一个指定的拒接策略。

线程创建之后,会不停从等待队列workQueue中拉取任务,workQueue是一个线程安全的阻塞队列,所以不存在线程安全问题,拉取到任务之后,执行任务逻辑。拉取任务时有两种情况:

1)线程池设置了keepAliveTime参数,并且此时线程池中的线程数量超过核心数量corePoolSize,从队列中拉取任务时会设置keepAliveTime为超时时间,超过这个时间之后,该线程不再等待任务,直接跑完run方法体,线程被回收;

2)否则线程会无限等待任务队列直到有任务到来。

219a2b6be229f41bd8e4dbb2cc30395e.png

拒绝策略(RejectedExecutionHandler)

当线程集合和等待队列都满时线程无法调度任务,这时线程池会执行一个默认的或使用者指定的拒绝策略。

JDK内置的拒绝策略主要有下面几种:

1)调用线程执行(CallerRunsPolicy),任务被线程池拒绝后,任务会被调用线程执行;

08e4275e24479eb0220acf8cb29b9335.png

2)终止执行(AbortPolicy),任务被拒绝时,抛出RejectedExecutionException异常报错

3)丢弃任务(DiscardPolicy),任务被直接丢弃,不会抛异常报错;

4)丢失老任务(DiscardOldestPolicy),把等待队列中最老的任务删除,删除后重新提交当前任务。

ade11a432d8cfa76d2e0d5ff5d18e027.png

除了这些内置的拒绝策略,使用者还可以实现RejectedExecutionHandler接口自定义拒绝策略

关闭线程池

关闭线程池时有两个关键步骤:

1)修改线程池状态到SHUTDOWN,这时新提交到线程池的任务都会被直接拒绝;

2)中断线程池中的所有线程,中断任务执行回收线程集合中所有线程。

71380f91a43d2179e80a5edf4ce16518.png

按时调度线程池(ScheduledThreadPoolExecutor)

JDK还内置了延时/定时调度任务的线程池,能够延时/定时执行提交的任务,它和普通线程池实现上的区别是,任务队列使用了定制的阻塞队列DelayedWorkQueue,该队列会对添加到队列中的任务按时间排序,在从队列中拉取任务时,只有队头任务指定的时间超过了延时时间时才会有任务出队,否则会一直等待。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值