【多线程】线程池

发布时间 2024-01-01 17:07:28作者: 此木|西贝

一、线程池的优势

  • 降低资源消耗。通过复用已创建的线程降低创建和销毁造成的消耗
  • 提高响应速度。当任务到达后,任务可以不需要等待线程创建就能立即执行。
  • 提高线程的可管理性。无节制的、随意的、不可控的创建线程会降低系统的稳定性以及提供不可控性。使用线程池可以统一管理、监控。

二、创建线程池

1、线程池参数

  • corePoolSize:核心线程数。线程池的基本大小,线程池创建初期,工作线程数为0,有任务提交时,会判断工作线程是否大于核心线程数,如果小于则无论是线程是否工作,都会创建新的线程,直到线程数达到核心线程数配置。(调用prestartAllCoreTherads()会在创建线程后根据核心线程数创建基本线程)
  • maximumPoolSize:最大线程数。如果队列满了且已创建的线程数小于最大线程数,则线程池会继续创建新的线程执行任务。(如果使用无界队列,则这个参数没有效果)
  • keepAliveTime:线程超时时间。如果线程数超过核心线程数且长时间不执行任务,则到设置时间后会进行回收。
  • unit:超时时间单位。时分秒毫秒等
  • workQueue:任务队列。用于保存等待执行的任务的阻塞队列(不建议使用无界队,列容易引起OOM)。
    • ArrayBlockingQueue:数组有界阻塞队列
    • LinkedBlockingQueue:链表有界阻塞队列(构造参数不填大小默认Integer.MAX_VALUE)
    • PriorityBlockingQueue:具有优先级的无界阻塞队列
  • threadFactory:用于设置创建线程的线程工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字
  • rejectedHandler:拒绝策略。当线程池的队列和线程都满了,设置对后续进入的任务处理的策略。
    • AbortPolicy:拒绝任务并抛出异常
    • CallerRunsPolicy:拒绝任务,交由调用者所处线程来执行任务
    • DiscardPolicy:拒绝任务并丢弃,无任何提示
    • DiscardOldestPolicy:丢弃队列中最新的任务,并执行当前任务

三、向线程池提交任务

  • execute():用于提交不需要返回值得任务,所以无法判断任务是否成功执行。参数实现Runnbale接口
  • submit():用于提交有返回值的任务。线程池会返回一个future类型对象,通过该对象判断任务是否执行成功。

四、合理配置线程池

  • IO密集型:由于线程不是一直在执行,则尽可能多的设置线程。线程数 = 2*CPU个数
  • CPU密集型:由于需要频繁使用CPU,所以配置尽可能小的线程。线程数 = CPU个数+1

五、线程池的执行原理

  • 线程池判断核心线程池中线程是否都在执行任务,
    • 否:线程存在直接执行;线程不存在,创建新的核心线程执行。
    • 是:添加到阻塞队列
  • 线程池判断阻塞队列是否已满
    • 否:新提交任务添加到队列中
    • 是:进行最大线程数的判断
  • 线程池判断是否达到最大线程数
    • 否:创建新的线程执行任务
    • 是:执行线程池拒绝策略
  • 线程池销毁非核心线程
    • 所有线程再任务队列中获取任务
    • 未获取到则阻塞设置的超时时间
      • 没有新任务,则进行线程回收,判断是否回收核心线程(allowCoreThreadTimeOut方法设置)
        • 不回收核心线程则回收至核心线程数结束
        • 回收核心线程,则超时时间后,无新任务线程池内没有存活线程
          image