线程池底层原理

什么是线程池?

答:  线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程(提高线程复用,减少性能开销)。线程池中线程的数量通常完全取决于可用内存数量和应用程序的需求。然而,增加可用线程数量是可能的。线程池中的每个线程都有被分配一个任务,一旦任务已经完成了,线程回到池子中然后等待下一次分配任务。

为什么要用线程池?(线程池的好处)

答: 1. 利用线程池管理和复用线程,控制并发数。

  • 避免线程创建和销毁造成资源消耗,产生过多垃圾会造成GC,影响性能
  • 在任务到达时,不需要等待线程创建,立即执行,提高性能
  • 线程是稀缺资源,过多创建会消耗系统资源,通过池化思想进行统一管理,监控和优化

       2. 实现任务队列缓存策略和拒绝机制。

       3. 实现与时间相关的功能,如 定时执行,周期执行等。

线程池状态

线程池和线程一样拥有自己的状态,在ThreadPoolExecutor类中定义了一个volatile变量runState来表示线程池的状态,线程池有四种状态,分别为RUNNING、SHURDOWN、STOP、TERMINATED。

  • 线程池创建后处于RUNNING状态。
  • 调用shutdown后处于SHUTDOWN状态,线程池不能接受新的任务,会等待缓冲队列的任务完成。
  • 调用shutdownNow后处于STOP状态,线程池不能接受新的任务,并尝试终止正在执行的任务。
  • 当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。

线程池底层执行原理

 线程池源码

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

 int corePoolSize (core:核心的) = > 表示常驻核心线程数
     如果等于0,则任务执行完之后,没有任何请求进入时销毁线程池的线程;
     如果大于0,即使本地任务执行完毕,核心线程也不会被销毁.
     这个值的设置非常关键;
     设置过大会浪费资源;
     设置过小会导致线程频繁地创建或销毁.

int maximumPoolSize  = >  表示线程池能够容纳同时执行的最大线程数

     最大线程数>=1

     如果待执行的线程数大于此值,需要借助第5个参数的帮助,缓存在队列中.
     如果maximumPoolSize = corePoolSize 即是固定大小线程池.

     最大线程数=核心线程数+非核心线程数

long keepAliveTime  = > 表示线程池中的线程空闲时间
    当空闲时间达到keepAliveTime时,线程会被销毁,直到只剩下corePoolSize个线程;
    避免浪费内存和句柄资源.
    在默认情况下,当线程池的线程数大于 corePoolSize 时 keepAliveTime 才起作用.
    但是当 ThreadPoolExecutor的 allCoreThreadTimeOut =True 时核心线程超时后也会被回收.

TimeUnit unit 表示时间单位

    keepAliveTime的时间单位通常是TimeUnit.SECONDS.

BlockingQueue<Runnable> workQueue表示缓存队列
    当请求的线程数大于maximumPoolSize时,线程进入BlockingQueue.
    后续示例代码中使用的LinkedBlockingQueue是单向链表,使用锁来控制入队和出队的原子性;
    两个锁分别控制元素的添加和获取,是一个生产消费模型队列.

ThreadFactory threadFactory 表示线程工厂

    它用来生产一组相同任务的线程;
    线程池的命名是通过给这个factory增加组名前缀来实现的.
    在虚拟机栈分析时,就可以知道线程任务是由哪个线程工厂产生的.

RejectedExecutionHandler handler
    当超过第5个参数workQueue的任务缓存区上限的时候,就可以通过该策略处理请求,这是一种简单的限流保护.
    友好的拒绝策略可以是如下三种:
      (1) 保存到数据库进行削峰填谷;在空闲时再提取出来执行
      (2)转向某个提示页面
      (3)打印日志

  • AbortPolicy:丢弃任务,抛出 RejectedExecutionException

  • CallerRunsPolicy:只用调用者所在线程来运行任务,有反馈机制,使任务提交的速度变慢)。

  • DiscardOldestPolicy
    若没有发生shutdown,尝试丢弃队列里最近的一个任务,并执行当前任务, 丢弃任务缓存队列中最老的任务,并且尝试重新提交新的任务

  • DiscardPolicy:不处理,丢弃掉, 拒绝执行,不抛异常
    当然,也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略.如记录日志或持久化存储不能处理的任务

注:自己学习总结的过程,有什么不好的地方,可以评论留言,互相学习。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值