zoukankan      html  css  js  c++  java
  • 并发与多线程【五】——线程池

    引言

    线程池通过复用线程,避免线程频繁地创建和销毁。Java 的 Executor 工具类中提供了 5 种类型的线程池创建方法,下面看下它们的特点和适用场景。

    线程池创建方法及使用场景

    如下图所示:

    1、固定大小线程池

    特点是线程数固定,使用无界队列,适用于任务数量不均匀的场景、对内存压力不敏感,但系统负载比较敏感的场景。

    2、Cached 线程池

    特点是不限制线程数,适用于要求低延迟的短期任务场景。

    3、单线程线程池

    就是一个线程的固定线程池,适用于需要异步执行但需要保证任务顺序的场景。

    4、Scheduled 线程池

    适用于定期执行任务场景,支持固定频率定期执行和固定延时定期执行两种方式。

    5、工作窃取线程池

    使用的是 ForkJoinPool,是固定并行度的多任务队列,适合任务执行时长不均匀的场景。

    线程池参数解析

    线程池除了工作窃取线程池外,都是通过 ThreadPoolExecutor 的不同参数初始化来创建的,创建参数列表如下图所示:

    第一个参数 corePoolSize:设置核心线程数。默认情况下核心线程会一直存活。

    第二个参数 maximumPoolSize:设置最大线程数。决定线程池最多可以创建多少线程。

    第三个参数 keepAliveTime 和第四个参数 unit:用来设置线程空闲时间和空闲时间的单位,当线程闲置超过空闲时间就会被销毁。可以通过 allowCoreThreadTimeOut 方法来允许核心线程被回收。

    第五个参数 workQueue:设置缓冲队列,设置线程池时常用的三个缓冲队列如上图左下角所示的 ArrayBlockingQueue、LinkedBlockingQueue、SychronousQueue。其中,ArrayBlockingQueue 是一个有界队列,就是指队列有最大容量限制。LinkedBlockingQueue 是一个无界队列,就是队列不限制容量。最后一个是 SynchronousQueue,是一个同步队列,内部没有缓冲区。

    第六个参数 threadFactory:设置线程池工厂方法,线程工厂用来创建新线程,可以对线程的一些方法进行定制,例如线程的 group、线程名、优先级等。一般使用默认工厂类即可。

    第七个参数 handler:设置线程池满时的拒绝策略。如上图右下角所示有四种拒绝策略,Abort 策略在线程池满后,提交新任务时会报 RejectedExecutionException,这个也是默认的拒绝策略。Discard 策略会在提交任务失败时对任务直接丢弃。CallerRuns 策略会在任务提交失败时,由提交任务的线程直接执行提交的任务。DiscardOldest 策略会丢弃最早提交的任务。

    上面说过的线程池都是使用怎样的参数创建的呢?

    • 固定大小线程池创建时,核心和最大线程数都设置成指定的线程数,这样线程池中就只会使用固定大小的线程数。
    • 队列使用无界队列 LinkedBlockingQueue。
    • Single 线程池就是设置线程数为1的固定线程池。
    • Cached 线程池的核心线程数设置为 0,最大线程数是 Integer.MAX_VALUE,主要是通过把缓冲队列设置成 SynchronousQueue,这样只要没有空闲线程就会新建。
    • Scheduled 线程池与前面几种不同的是使用了 DelayedWorkQueue,这是一种按延迟时间获取任务的优先级队列。

    线程池执行流程

    向线程池提交任务时,可以使用 execute 和 submit,区别就是 submit 可以返回一个 future 对象,通过该对象可以了解任务执行情况,可以取消任务的执行,还可以获取执行结果或执行异常。submit 最终也是通过 execute 执行的。执行流程如下图所示:

    向线程池提交任务时,会首先判断线程池中的线程数是否大于设置的核心线程数,如果不大于,就创建一个核心线程来执行任务。 

    如果大于核心线程数,会判断缓冲队列是否满了,如果没有满,则放入队列,等待线程空闲时,执行任务。

    如果队列已经满了,会判断是否达到了线程池设置的最大线程数,如果没有达到,就创建新线程执行任务。

    如果达到了最大线程数,则执行指定的拒绝策略。

    需要注意的是,队列的判断是先于最大线程数判断的,顺序不要搞反。

  • 相关阅读:
    git或gitee 提交代码到远程仓库
    gitee 创建代码仓库,并提交本地代码
    Logback 实现日志链路追踪
    navicat 查看,设计并导出数据库 ER图
    Jackson 使用 @JsonFormat 注解进行时间格式化
    Redis 缓存常见问题
    jedis 与 redission 实现分布式锁
    Redis 集群模式搭建
    Redis 哨兵模式高可用
    Notepad++ 正则表达式提取信息
  • 原文地址:https://www.cnblogs.com/yadongliang/p/12325618.html
Copyright © 2011-2022 走看看