zoukankan      html  css  js  c++  java
  • 线程池

    线程池

    简介

    缓存已创建的线程,以备执行后续的任务。

    目的:
    创建和销毁消除消耗系统的资源,通过缓存已创建的线程,避免频繁的创建线程,从而减少系统的消耗。


    与线程池有关的类和接口

    • Executor :底层接口,定义了 execute() ,表示执行传进来的任务。
    • ExecutorService :继承自 Executor ,声明了一些常用方法: submit , invokeAll , invokeAny , shutDown 。
    • AbstractExecutorService :实现 ExecutorService 接口,基本实现 ExecutorService 中的方法。
    • ThreadPoolExecutor :继承自 AbstractExecutorService 。 execute() :向线程池提交一个任务,由线程池执行。 submit() :向线程池提交任务,可以返回任务执行的结果。 shutdown() 关闭线程。 shutdownNow() :立即关闭线程池。

    线程池的参数

    • corePoolSize :核心池的大小。创建线程池默认没有线程,得到任务到达时才创建线程。当线程数目到达 corePoolSize 时,会把后续的任务放入缓存队列中。
    • maximumPoolSize :线程池的最大线程数。表示线程池中所能容纳的最大的线程数量。
    • keepAliveTime :表示线程在没有执行任务,存活多久后被终止。当线程池中的线程大于 corePoolSize 时,会对超过数量的线程统计空闲时间,然后超过 keepAliveTime 的线程会被终止,直到线程池中的线程数量不超过 corePoolSize 。
    • unit :超时时间单位。
    • workQueue :阻塞队列,用来存储等待执行的任务。
    • threadFactory :线程工厂,创建一个新线程时使用的工厂,可以设定线程名,是否为守护线程。
    • handler :拒绝策略,当等待队列中的任务达到最大限制,并且线程池中线程数达到最大限制时,若有新的任务到达,则采取的拒绝策略。

    线程池的状态

    • RUNNING = 0 :线程池创建完后初始化。
    • SHUTDOWN = 1 :调用 shutdown() 方法,线程池不再接受新的任务,等待现有任务执行完。
    • STOP = 2 :调用 shutdownNow() 方法,线程池不接受新的任务,并且终止正在执行的任务。
    • TERMINATED = 3 :线程池处于SHUTDOWN或STOP状态,并且工作线程已被销毁,任务队列已被清空,则进入TERMINATED状态。

    线程池执行流程

    流程:

    1. 如果当前线程池中的线程数目 小于  < corePoolSize 。则对于每个新任务,都会创建一个线程去执行这个任务。
    2. 如果当前线程池中的线程数目 大于等于 >= corePoolSize 。对于每个新任务,会将其添加到任务队列中。若添加成功,则任务由空闲的线程主动将其从队列中移除后执行。若添加失败(任务队列已满),则尝试创建新的线程执行。
    3. 若当前线程池中的线程数目到达 maximumPoolSize ,则对于新任务采取拒绝策略。
    4. 如果线程池中的数量大于 corePoolSize 时,如果某个线程空闲时间超过 keepAliveTime ,线程会被终止,直到线程池中的线程数目不超过 corePoolSize 。
    5. 如果为核心线程池中的线程设置存活时间,则当核心线程池中的线程空闲时间超过 keepAliveTime ,则该线程也会被终止。

    线程池的初始化

    • 默认情况下,创建线程池后,线程池中没有线程。需要在提交任务后才创建线程。
    • 可以通过两个方法在创建线程池后创建线程:
      • prestartCoreThread() :初始化一个线程。
      • prestartAllCoreThread():初始化所有核心线程。

    任务队列和排队策略

    workQueue :用来存放等待执行的任务。类型为 BlockingQueue<Runnable> 。

    阻塞队列

    分类:

    • FIFO:先进先出。先进入队列中的元素最先出队列。
    • LIFO:先进后出。后进入队列的元素最先出队列。

    操作

    • 插入 :当队列已满时,生产者线程插入数据会被阻塞,直到消费者消耗队列中的数据使得队列有空闲空间。
    • 获取 :当队列为空时,消费者线程获取数据时会被阻塞,直到生产者向队列中插入数据。

    方法

    • 插入数据:
      • offer() :添加数据成功返回true,添加失败返回false。(若没有设置超时时间,则直接返回;若设置超时时间,则等待指定的超时时间,超时时间过期后返回false)
      • put() :添加数据成功则直接返回,添加失败会被一直阻塞。
    • 获取数据:
      • poll() :若队列有元素,则获取队首元素;否则直接返回null。(若设置超时时间,则未成功获取元素时阻塞等待,直到超时返回null或成功获取元素)
      • take() :若队列非空,则直接返回队列首部元素;否则一直阻塞,直到成功获取元素或被中断。

    类型:

    • ArrayBlockingQueue :基于 数组 的FIFO队列,创建时必须指定大小,内部使用定长数组缓存数据。读写数据同用同一个锁对象(可以使用锁分离实现生产者和消费者的并行,但 ArrayBlockingQueue 的读写为轻量级,使用锁分离只会增加复杂度。),可以采用公平锁或非公平锁。
    • LinkedBlockingQueue :基于 链表 的FIFO队列,可以不指定大小,则大小为 Integer.MAX_VALUE 。对于生产者和消费者采用独立的锁进行同步,生产者和消费者可以并发操作队列中的数据。(若没有设置初始容量可能由于线程过多导致内存耗尽)
    • synchronousQueue :一种没有缓冲的等待队列。不保存提交的任务,而是直接创建一个新线程执行新的任务。
      • 若为 公平模式 :采用公平锁,并使用FIFO队列阻塞生产者和消费者。
      • 若为 非公平模式 :采用非公平锁,使用LIFO队列管理阻塞的生产者和消费者。
    • DelayQueue :队列中元素只有在指定的延迟时间到了才能获取到。生产者线程不会被阻塞,消费者线程在队列为空或者没有元素到期时会被阻塞。
    • PriorityBlockingQueue :基于优先级的阻塞队列。不会阻塞生产者。当队列中没有元素时,阻塞消费者。采用公平锁。

    拒绝策略

    情景

    当线程池中的线程达到 maximumPoolSize ,并且任务队列已满,此时对于新来的任务采取拒绝策略进行处理。

    分类

    • AbortPolicy :抛弃任务,并抛出异常。
    • DiscardPolicy :直接抛弃任务,但不抛出异常。
    • DiscardOldPolicy :抛弃任务队列中最前的任务(最老的任务),然后尝试执行新任务。
    • CallerRunPolicy :由调用线程处理任务。

    线程池的关闭

    • shutdown() :不会立即终止线程池,而是不再接受新的任务,并且等待所有任务缓存队列中的任务都执行完后才终止。
    • shutdownNow() :立即终止线程池,并打断正在执行的任务,清空任务队列,返回尚未执行的任务。

    线程池容量的动态调整

    • setCorePoolSize() :设置核心池的大小。
    • setMaximumPoolSize() :设置线程池最大能创建线程的数目。

    配置线程池的参数

    根据任务的类型进行配置。

    • CPU密集型任务: corePoolSize 设置为CPU核心数+1;
    • IO密集型任务: corePoolSize 设置为2*CPU核心数。

    Executors 创建四种线程池

    提供一系列工厂方法来创建线程池。

    • newCachedThreadPool :一个可缓存线程池,通过 execute 重用已经构建的线程。若没有可用线程,则创建新线程并添加到线程池中。终止超时未使用(60s)的线程。
    • newFixedThreadPool :一个固定线程数量的线程池,控制线程的最大并发数,超过的线程在队列中等待。
    • newScheduledThreadPool :一个定长的线程池,支持定时以及周期性任务执行。
    • newSingleThreadExecutor :一个单线程的线程池,使用一个工作线程,保证任务按照FIFO,LIFO顺序执行。

    newCachedThreadPool

    • 先查看线程池中有没有已创建的线程,若有,则进行复用;否则创建一个新的线程加入池中。
    • 适用于 执行周期短的异步任务 。
    • 超时没有被使用的线程会被终止。

    newFixedThreadPool

    • 任意时刻只有固定数量的活动线程存在。
    • 没有可用的线程时,新来的任务会被放入等待队列中。

    newScheduledThreadPool

    • 有两种定期执行任务:
      • 固定延迟执行:当前一个任务执行完成后,固定时延后执行新的任务。
      • 固定频率执行:当前一个任务执行时,固定时延后执行,不管前一个任务是否执行完成。

    newSingleThreadExecutor

    • 单例线程池,任意时刻只有一个线程。
  • 相关阅读:
    Android Market google play store帐号注册方法流程 及发布应用注意事项【转载】
    cocos2d-x 调用第三方so文件
    ios cocos2d-x 多点触摸
    linux文件分割(将大的日志文件分割成小的)
    Linux 统计某个字符串出现的次数
    scapy基础-网络数据包结构
    mac 下idea光标问题
    mac ox终端显示 bogon的问题
    hibernate和mybatis的区别
    memcached知识点梳理
  • 原文地址:https://www.cnblogs.com/truestoriesavici01/p/13662895.html
Copyright © 2011-2022 走看看