gball个人知识库
首页
基础组件
基础知识
算法&设计模式
  • 操作手册
  • 数据库
  • 极客时间
  • 每日随笔
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 画图工具 (opens new window)
关于
  • 网盘 (opens new window)
  • 分类
  • 标签
  • 归档
项目
GitHub (opens new window)

ggball

后端界的小学生
首页
基础组件
基础知识
算法&设计模式
  • 操作手册
  • 数据库
  • 极客时间
  • 每日随笔
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 画图工具 (opens new window)
关于
  • 网盘 (opens new window)
  • 分类
  • 标签
  • 归档
项目
GitHub (opens new window)
  • 面试

  • 数据库

  • linux

  • node

  • tensorFlow

  • 基础组件

  • 基础知识

    • java集合

    • jvm调优

    • java并发编程

      • 进程与线程
      • 多线程的方法介绍与使用
      • 线程死锁
      • 守护线程与用户线程
      • ThreadLocal了解
      • 什么是多线程并发编程
      • unsafe类了解
      • 伪共享
      • 锁的了解
      • ThreadLocalRandom原理解析
      • LongAdder,LongAccumulator类了解
      • 实践-创建多少线程合适
      • 线程通信——通知与等待
      • 缓存一致性问题
      • 利用Excutors异步执行任务
      • 线程池
        • 线程池是如何创建的?
          • 线程池的主要参数
        • 线程池的执行过程?
        • 配置线程池最大线程数
        • 线程池的关闭
        • 拒绝策略
      • 线程池操作数据库造成死锁
      • Java 浅拷贝和深拷贝的理解和实现方式
      • java内存模型JMM
      • 锁升级过程
      • io模型
      • 关键字介绍
      • AQS解析
    • java网络编程

    • java8新特性

    • javaAgent

    • java高级

  • 算法与设计模式

  • 分布式

  • 疑难杂症

  • go学习之旅

  • 极客时间

  • 知识库
  • 基础知识
  • java并发编程
ggball
2021-10-08

线程池

# 线程池是如何创建的?

JAVA中创建线程池主要有两类方法,一类是通过Executors工厂类提供的方法,该类提供了4种不同的线程池可供使用。另一类是通过ThreadPoolExecutor类进行自定义创建。

Executors工厂类


// 五种线程池:
//     ExecutorService threadPool = null;
//     threadPool = Executors.newCachedThreadPool();//有缓冲的线程池,线程数 JVM 控制
//     threadPool = Executors.newFixedThreadPool(3);//固定大小的线程池
//     threadPool = Executors.newScheduledThreadPool(2); // 具有延时,定时功能
//     threadPool = Executors.newSingleThreadExecutor();//单线程的线程池,只有一个线程在工作
//     threadPool = new ThreadPoolExecutor();//默认线程池,可控制参数比较多   

private static void createCachedThreadPool() {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(() -> {
                // 获取线程名称,默认格式:pool-1-thread-1
                System.out.println(DateUtil.now() + " " + Thread.currentThread().getName() + " " + index);
                // 等待2秒
                sleep(2000);
            });
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

ThreadPoolExecutor类

ThreadPoolExecutor提供构造方法,需要自己设置具体的参数,更加灵活

public ThreadPoolExecutor(int corePoolSize, // 核心线程数
                              int maximumPoolSize, // 最大工作线程
                              long keepAliveTime, // 存活时间,线程没有任务执行时最多保持多久时间会终止。
                              TimeUnit unit, // 时间单位
                              BlockingQueue<Runnable> workQueue, // 工作队列
                              ThreadFactory threadFactory, // 线程工厂,主要用来创建线程,默及正常优先级、非守护线程。
                              RejectedExecutionHandler handler // 拒绝策略,当创建新线程使线程数大于最大线程的情况下,会执行
                              ) {
        // 省略...
    }
1
2
3
4
5
6
7
8
9
10

# 线程池的主要参数

  • corePoolSize 核心线程数 核心线程数,线程池中始终存活的线程数。

  • BlockingQueue 工作队列 workQueue = new ArrayBlockingQueue<>(5);//基于数组的先进先出队列,有界 workQueue = new LinkedBlockingQueue<>();//基于链表的先进先出队列,无界 workQueue = new SynchronousQueue<>();//无缓冲的等待队列,无界

  • threadFactory 线程工厂 用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的。线程设置更有意义的名字。使用开源框架 guava 提供的 ThreadFactoryBuilder 可以快速给线程池里的线程设置有意义的名字,代码如下:

new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build();
1
  • handler 拒绝策略,拒绝处理任务时的策略,4种可选,默认为AbortPolicy。
参数 描述
AbortPolicy 拒绝并抛出异常
CallerRunsPolicy 只用调用者所在线程来运行任务
DiscardOldestPolicy 抛弃队列头部(最旧)的一个任务,并执行当前任务。
DiscardPolicy 抛弃当前任务。
 RejectedExecutionHandler rejected = null;
    rejected = new ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常
    rejected = new ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常
    rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列
    rejected = new ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行
1
2
3
4
5

# 线程池的执行过程?

20230211161701

  1. 主线程提交任务到线程池,如果当前线程数小于核心线程数,创建新的线程用于执行任务,如果不是,下一步。
  2. 此时核心线程已满,再判断工作队列存放的线程数是否满了,如果没有满,则放入工作队列,如果不是,下一步。
  3. 此时工作队列满了,再看当前线程数是否等于最大线程数,如果是的话,执行拒绝策略,如果不是,创建新的线程,执行任务。

# 配置线程池最大线程数

  • cpu密集型 maximumPoolSize = n*cpu + 1
  • io密集型 maximumPoolSize = 2 * n * cpu

# 线程池的关闭

可以通过调用线程池的 shutdown 或 shutdownNow 方法来关闭线程池。 相同点:遍历所有的工作线程,然后interrupt掉线程 不同点:shutdown 调用后,不再接受新的任务,但是会等待正在运行的线程,停止没有执行任务的线程。 shutdownNow 调用后会尝试停止正在运行或暂停任务的线程。

# 拒绝策略

  • CallerRunsPolicy - 当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。但是,由于调用者自己运行任务,如果任务提交速度过快,可能导致程序阻塞,性能效率上必然的损失较大
  • AbortPolicy - 丢弃任务,并抛出拒绝执行 RejectedExecutionException 异常信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行。
  • DiscardPolicy - 直接丢弃,其他啥都没有
  • DiscardOldestPolicy - 当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入
上次更新: 2025/06/04, 15:06:15
利用Excutors异步执行任务
线程池操作数据库造成死锁

← 利用Excutors异步执行任务 线程池操作数据库造成死锁→

最近更新
01
AIIDE
03-07
02
githubActionCICD实战
03-07
03
windows安装Deep-Live-Cam教程
08-11
更多文章>
Theme by Vdoing
总访问量 次 | 总访客数 人
| Copyright © 2021-2025 ggball | 赣ICP备2021008769号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×

评论

  • 评论 ssss
  • 回复
  • 评论 ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
  • 回复
  • 评论 ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
  • 回复
×