NipGeihou's blog NipGeihou's blog
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档

NipGeihou

我见青山多妩媚,料青山见我应如是
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档
  • 设计模式

  • 开发规范

  • 经验分享

  • 记录

  • 快速开始

  • 笔记

    • 多线程与并发

      • 前言
      • 理论基础
      • Java中各种锁的概念
      • 关键字:synchronized
      • 关键字:volatile
      • 关键字:final
      • Java多线程 - 线程池
        • 为什么要有线程池?
        • 如何创建?
          • Executors 线程池工具类
          • newFixedThreadPool(指定线程数线程池)
          • newSingleThreadExecutor(单线程线程池)
          • newCachedThreadPool(动态扩容线程池)
          • ThreadPoolExecutor 自定义线程池
          • 参数
        • 新任务流程图
        • 回收空闲线程
        • 参考资料
      • Java多线程 - Block Queue阻塞队列
      • Java多线程 - 辅助类
      • Java多线程 - CompletableFuture
      • Java多线程 - 线程变量传递ThreadLocal
    • JDK

    • Java集合

    • Spring

    • JVM

    • Other

  • 面试题

  • 微服务

  • 踩过的坑

  • Java
  • 笔记
  • 多线程与并发
NipGeihou
2022-02-13
目录

Java多线程 - 线程池

# 为什么要有线程池?

线程池能够对线程进行统一分配,调优和监控:

  • 降低资源消耗(线程无限制地创建,然后使用完毕后销毁)
  • 提高响应速度(无须创建线程)
  • 提高线程的可管理性

池化技术

池化技术指的是提前准备一些资源,在需要时可以重复使用这些预先准备的资源。

也就是说池化技术有两个优点:

  1. 提前创建;
  2. 重复利用。

常见的池化技术的使用有:线程池、内存池、数据库连接池、HttpClient 连接池等

# 如何创建?

# Executors 线程池工具类

# newFixedThreadPool(指定线程数线程池)

newFixedThreadPool(int nThreads)
  • workQueue.capacity = Integer.MAX_VALUE :任务队列无限长

# newSingleThreadExecutor(单线程线程池)

newSingleThreadExecutor()
  • workQueue.capacity = Integer.MAX_VALUE :任务队列无限长

# newCachedThreadPool(动态扩容线程池)

newCachedThreadPool()
  • maximumPoolSize = Integer.MAX_VALUE :最大线程数无限大

以上方法均返回 ExecutorService 接口对象

点击查看
ExecutorService executorService = Executors.newFixedThreadPool(1);

// 只能提交Runnable类型的任务
executorService.execute(() -> {
    // 会直接抛出任务执行时的异常
    System.out.println("hello world");
});

// submit既能提交Runnable类型任务也能提交Callable类型任务
executorService.submit(() -> {
    // 不抛出任务执行时的异常
    System.out.println("hello world");
});

// 关闭线程池
executorService.shutdown();

execute 和 submit 的区别与联系

点击查看
  • execute 和 submit 都属于线程池的方法,execute 只能提交 Runnable 类型的任务,而 submit 既能提交 Runnable 类型任务也能提交 Callable 类型任务。

  • execute 会直接抛出任务执行时的异常,submit 会吃掉异常,可通过 Future 的 get 方法将任务执行时的异常重新抛出。

  • execute 所属顶层接口是 Executor,submit 所属顶层接口是 ExecutorService,实现类 ThreadPoolExecutor 重写了 execute 方法,抽象类 AbstractExecutorService 重写了 submit 方法。

笔记

三个工具类方法,在 workQueue.capacity 或是 maximumPoolSize 上使用了 Integer.MAX_VALUE 容易导致 OOM(Out Of Memory),在阿里巴巴开发手册中不推荐使用,而是自己定义。

# ThreadPoolExecutor 自定义线程池

# 参数

  • int corePoolSize :常驻核心线程数(常驻柜台数)
  • int maximumPoolSize :最大线程数(最大柜台数)
    • CPU 密集型的任务,电脑核心数 + 1( Runtime.getRuntime().availableProcessors() + 1 )
    • IO 密集型的任务,电脑核心数 / 阻塞系数( 阻塞时间 / (阻塞时间 + 计算时间) )
  • long keepAliveTime :与下面一个参数配合使用
  • TimeUnit unit :当空闲的时间达到 keepAliveTime unit 时销毁多余的线程
  • BlockingQueue<Runnable> workQueue :任务队列,被提交但尚未被执行的任务(候客区)
  • ThreadFactory threadFactory :表示线程池中的工作线程的线程工厂,用于创建线程。一般默认的即可(Executors.defaultThreadFactory ())
  • RejectedExecutionHandler handler :拒绝策略,表示当队列满了,并且工作线程大于等于 maximumPoolSize 时如何来拒绝请求执行的任务 (runable) 的策略
    • new ThreadPoolExecutor.AbortPolicy() :(默认)直接抛出 RejectedExecutionException 异常阻止系统正常运行
    • new ThreadPoolExecutor.CallerRunsPolicy() :调用者运行,一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退调用者,从而降低新任务的流量。(main 线程找线程池处理,处理不了,返回 main 处理)
    • new ThreadPoolExecutor.DiscardPolicy() :该策略默默地丢弃无法处理的任务,不予任何处理、不抛异常。如果允许任务丢失,这是最好的一种策略
    • new ThreadPoolExecutor.DiscardOldestPolicy() :将队列中最久的任务丢弃,将当前任务放进来。

# 新任务流程图

image-20221216161951083

工作核心数与队列的关系

  • 当任务数量大于核心线程数时,将任务加入阻塞队列
  • 当阻塞队列满了,依次扩容核心线程数直至最大线程数
  • 当达到最大线程数,再次提交任务,将执行拒绝策略

# 回收空闲线程

# 参考资料

  • java - 线程池是怎么回收空闲线程的?如果你认为有定时任务,那你就错了! - 个人文章 - SegmentFault 思否 (opens new window)
上次更新: 2024/03/11, 22:37:05
关键字:final
Java多线程 - Block Queue阻塞队列

← 关键字:final Java多线程 - Block Queue阻塞队列→

最近更新
01
Docker Swarm
04-18
02
安全隧道 - gost
04-17
03
Solana最佳实践
04-16
更多文章>
Theme by Vdoing | Copyright © 2018-2025 NipGeihou | 友情链接
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式