zoukankan      html  css  js  c++  java
  • 线程池的那些事其一

     

    一,什么是线程池?

       简单来说,管理线程的池子。帮我们重复管理线程,避免创建大量的线程增加开销。

    二,为什么用线程池?

    1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

    2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。

    3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

    三,什么时候用线程池?

    1. 单个任务处理时间比较短

    2. 需要处理的任务数量很大

    四,解读线程池的原理

      A,七个核心参数

      1,corePoolSize,核心线程数量

      默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中

      2,maximumPoolSize,线程数最大值

      3,keepLiveTime,多长时间被回收

      默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

      4,timeUnit,设置keepLiveTime的时间单位,共7种单位:d, h, m, s, ms, mis, ns 

      5,workQueue,存放提交至线程池但未被执行的任务

      ArrayBlockingQueue(有界队列),是一个用数组实现的有界阻塞队列,按FIFO排序量。

      LinkedBlockingQueue(可设置容量队列),基于链表结构的阻塞队列,按FIFO排序任务,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQuene;newFixedThreadPool线程池使用了这个队列

      DelayQueue(延迟队列),是一个任务定时周期的延迟执行的队列。根据指定的执行时间从小到大排序,否则根据插入到队列的先后排序。newScheduledThreadPool线程池使用了这个队列。

      PriorityBlockingQueue(优先级队列),是具有优先级的无界阻塞队列;

      SynchronousQueue(同步队列),一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene,newCachedThreadPool线程池使用了这个队列。

      6,threadFactory,创建线程的工厂

      用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

    使用开源框架guava提供的ThreadFactoryBuilder可以快速给线程池里的线程设置有意义的名字,code: new ThreadFactoryBuilder().setNameFormat("Hello-Engine").build();

      7,rejectedExecutionHandler,拒绝策略设置

      CallerRunsPolicy:只要线程池没关闭,就用调用者所在线程来运行任务

      AbortPolicy:直接抛RejectedExecutionException 异常

      DiscardPolicy:不处理,直接扔了

      DiscardOldestPolicy:把队列里待最久的那个任务扔了,并执行当前任务

      支持实现自己的 RejectedExecutionHandler 接口自定义策略,如记录日志类。

      B,线程池的状态

    RUNNING

    • 该状态的线程池会接收新任务,并处理阻塞队列中的任务;

    • 调用线程池的shutdown()方法,可以切换到SHUTDOWN状态;

    • 调用线程池的shutdownNow()方法,可以切换到STOP状态;

    SHUTDOWN

    • 该状态的线程池不会接收新任务,但会处理阻塞队列中的任务;

    • 队列为空,并且线程池中执行的任务也为空,进入TIDYING状态;

    STOP

    • 该状态的线程不会接收新任务,也不会处理阻塞队列中的任务,而且会中断正在运行的任务;

    • 线程池中执行的任务为空,进入TIDYING状态;

    TIDYING

    • 该状态表明所有的任务已经运行终止,记录的任务数量为0。

    • terminated()执行完毕,进入TERMINATED状态

    TERMINATED

    • 该状态表示线程池彻底终止

     

      C,任务执行流程

      1,execute()方法

      a,主要流程图如下:

      b,ThreadPoolExecutor执行流程

    • 提交一个任务,线程池里存活的核心线程数小于线程数corePoolSize时,线程池会创建一个核心线程去处理提交的任务。

    • 如果线程池核心线程数已满,即线程数已经等于corePoolSize,一个新提交的任务,会被放进任务队列workQueue排队等待执行。

    • 当线程池里面存活的线程数已经等于corePoolSize了,并且任务队列workQueue也满,判断线程数是否达到maximumPoolSize,即最大线程数是否已满,如果没到达,创建一个非核心线程执行提交的任务。

    • 如果当前的线程数达到了maximumPoolSize,还有新的任务过来的话,直接采用拒绝策略处理。

     

       c,源码解读

     2,submit()方法

    ps: 线程池抛异常了,如何处理?

     

    五,怎样使用线程池?

    A,Executors常用方法及问题

     1,常用方法四种:

    newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

     

    工作机制:

     

    适用场景:用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。

    •  

    newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

     

    工作机制:

     

    适用场景:用于串行执行任务的场景,一个任务一个任务地执行。

    •  

    newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

     

    工作机制:

           

     

    适用场景:用于并发执行大量短期的小任务。

    •  

    newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

     

    工作机制:

     

    • 适用场景: 周期性执行任务的场景,需要限制线程数量的场景

     

     2,使用Executors的问题, 来自阿里Java规范的建议:

           

    B,自定义线程池

    1,合理配置线程池

         通常我们是需要根据这批任务执行的性质来确定的。

    • IO 密集型任务:由于线程并不是一直在运行,所以可以尽可能的多配置线程,比如 CPU 个数 * 2

    • CPU 密集型任务(大量复杂的运算)应当分配较少的线程,比如 CPU 个数相当的大小。

         当然这些都是经验值,最好的方式还是根据实际情况测试得出最佳配置。

    2,推荐使用Guava提供的ThreadFactoryBuilder来创建线程池
         

     

     

     

     

  • 相关阅读:
    搜索条件中的模式匹配,及包含关键字条件匹配
    Makefile用法,详细到让人吐。
    循序渐进实现仿QQ界面(三):界面调色与控件自绘
    VC 多线程编程
    用UDL快速生成一个数据库连接字符串。
    VC CMarkup所有方法说明
    VC判断控件是否按钮。
    学习笔记(一)
    libvirt0.8.2安装(方法一)
    centos中kvm网桥的设置
  • 原文地址:https://www.cnblogs.com/Jashinck/p/15115875.html
Copyright © 2011-2022 走看看