线程池实现“线程复用”的原理

线程池实现“线程复用”的原理

学习线程复用的原理,以及对线程池的 execute 这个非常重要的方法进行源码解析。

线程复用原理

我们知道线程池会使用固定数量或可变数量的线程来执行任务,但无论是固定数量或可变数量的线程,其线程数量都远远小于任务数量,面对这种情况线程池可以通过线程复用让同一个线程去执行不同的任务,那么线程复用背后的原理是什么呢?

线程池可以把线程和任务进行解耦,线程归线程,任务归任务,摆脱了之前通过 Thread 创建线程时的一个线程必须对应一个任务的限制。在线程池中,同一个线程可以从 BlockingQueue 中不断提取新任务来执行,其核心原理在于线程池对 Thread 进行了封装,并不是每次执行任务都会调用 Thread.start() 来创建新线程,而是让每个线程去执行一个“循环任务”,在这个“循环任务”中,不停地检查是否还有任务等待被执行,如果有则直接去执行这个任务,也就是调用任务的 run 方法,把 run 方法当作和普通方法一样的地位去调用,相当于把每个任务的 run() 方法串联了起来,所以线程数量并不增加。

我们首先来复习一下线程池创建新线程的时机和规则:

如流程图所示,当提交任务后,线程池首先会检查当前线程数,如果此时线程数小于核心线程数,比如最开始线程数为0,则新建线程并执行任务,随着任务的不断增加,线程数会逐渐增加并达到核心线程数。此时如果任有任务被不断提交,就会被放入waitQueue任务队列中,等待核心线程执行完当前任务后重新从workQueue中提取正在等待被执行的任务。

此时,假设我们的任务特别多,已经达到了workQueue的容量上限,这时线程池就会启动后备力量,也就是maxPoolSize,线程池会在corePoolSize核心线程数的基础上继续创建线程来执行任务,假设任务被不断提交,线程池会持续创建线程知道线程数达到maxPoolSize最大线程数,如果依然有任务提交,这就超过了线程池的最大处理能力,这个时候线程池就会拒绝这些任务,我们可以看到实际上任务进来之后,线程池会逐一判断corePoolSize、workQueue、maxPoolSize,如果依然不能满足需求,则会拒绝任务。

我们接下来具体看看代码是如何实现的,我们从execute方法开始分析,源码如下所示:

上面这段代码是Java线程池中 execute方法的实现部分。

  1. 首先会检查当前线程池的状态,包括正在运行的线程数量和线程池状态等信息。
  2. 如果正在运行的线程数量小于核心线程数 corePoolSize,那么会尝试启动一个新的线程来执行任务。这里使用 addWorker 方法来启动新线程,并将任务传递给它执行。
  3. 如果任务能够成功地加入到任务队列中(这里使用了 workQueue.offer(command)),那么会进行进一步检查:
    • 再次检查线程池的运行状态,确保没有在方法开始时线程池已经关闭。
    • 如果发现之前有线程死亡或线程池已经关闭,就会回滚将任务加入到任务队列的操作。
    • 如果发现当前线程池中没有运行的线程,会尝试添加一个新的线程来执行任务。
  4. 如果任务无法加入到任务队列中,会再次尝试添加一个新的线程来执行任务。

先有个整体把握,接下来逐行分析。首先看下前几行:

//如果传入的Runnable的空,就抛出异常
if (command == null) 
    throw new NullPointerException()<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值