线程池相关详解

简介: 线程池相关详解

1.线程池的核心参数

线程池核心参数主要参考ThreadPoolExecutor这个类的7个参数的构造函数

  • corePoolSize核心线程数目


  • maximumPoolSize最大线程数目=(核心线程+救急线程的最大数目)


  • keepAliveTime生存时间:救急线程的生存时间,生存时间内没有新任务,此线程资源会释放


  • unit时间单位:救急线程的生存时间单位,如秒、毫秒等


  • workQueue当没有空闲核心线程时,新来任务会加入到此队队列里,队列满会创建救急线程执行任务


  • threadFactory线程工厂:可以定制线程对象的创建,如设置线程名字、是否守护线程等


  • handler拒绝策略:当所有线程都在繁忙,workQueue也放满时,会触发拒绝策略

工作流程:

  1. 任务在提交的时候,首先判断核心线程数是否已满,如果没有满则直接添加到工作线程执行。
  2. 如果核心线程满了,则判断阻塞队列是否已满,如果没有满,当前任务存储阻塞队列。
  3. 如果阻塞队列也满了,则判断线程数是否小于最大线程数,如果满足条件,则使用临时线程执行任务。【如果核心或临时线程执行完成任务后会检查阻塞队列中是否有需要执行的线程,如果有,则使用非核心线程执行任务】
  4. 如果所有线程都忙着(核心线程+临时线程)则走拒绝策略。


拒绝策略:

  • AbortPolicy:直接抛出异常,默认策略
  • CallerRunPolicy:用调用者所在的线程来执行任务
  • DiscardOldestPolicy:丢弃阻塞队列中靠前的任务,并执行当前任务
  • DiscardPolicy:直接丢弃任务

2.线程池常见的阻塞队列

常见的有4个,最多用的是ArrayBlockingQueue和LinkedBlockingQueue


  1. ArrayBlockingQueue:基于数组结构的有界阻塞队列FIFO
  2. LinkedBlockingQueue:基于链表结构的有界阻塞队列FIFO
  3. DeayedWorkQueue:是一个优先级队列,可以保证每次出队的任务都是当前队列中执行时间最靠前的
  4. SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作


ArrayBlockingQueue和LinkedBlockingQueue的区别:


左边是LinkedBlockingQueue加锁的方式,右边是ArrayBlockingQueue加锁的方

  • LinkedBlockingQueue读和写各有一把锁,性能相对较好
  • ArrayBlockingQueue只有一把锁,读和写公用,性能相对于
  • LinkedBlockingQueue差一些

3.如何确定核心线程数

设置核心线程数之前,需要熟悉一些执行线程池任务的类型:

  • IO密集型任务:文件读写、DB读写、网络请求
    推荐:核心线程数大小设置为2N+1(N为CPU数)
  • CPU密集型任务:计算型代码、Bitmap转换、Gson转换等

推荐:核心线程数大小设置为N+1


① 高并发、任务执行时间短 -->( CPU核数+1 ),减少线程上下文的切换


② 并发不高、任务执行时间长


IO密集型的任务 --> (CPU核数 * 2 + 1)


计算密集型任务 --> ( CPU核数+1 )③ 并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整


体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器


是第二步,至于线程池的设置,设置参考(2)

4.线程池的种类

  • 创建使用固定线程数的线程池
  • 单线程化的线程池
  • 可缓存线程池
  • 提供了“延迟”和“周期执行”功能的ThreadPoolExecutor

1.创建使用固定线程数的线程池

  • 核心线程数与最大线程数一样,没有救急线程
  • 阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE
  • 场景:适用于任务量已知,相对耗时的任务

2.单线程化的线程池,它只会用唯一的工作线程来执行任 务,保证所有任务按

照指定顺序(FIFO)执行

  • 核心线程数和最大线程数都是1
  • 阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE
  • 适用场景:适用于按照顺序执行的任务

3.可缓存线程池

  • 核心线程数为0
  • 最大线程数是Integer.MAX_VALUE
  • 阻塞队列为SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作。


适用场景:适合任务数比较密集,但每个任务执行时间较短的情况


4.提供了“延迟”和“周期执行”功能的ThreadPoolExecutor


适用场景:有定时和延迟执行的任务

5.为什么不建议用Executors创建线程池

6.CountDownLatch

CountDownLatch(闭锁/倒计时锁)用来进行线程同步协作,等待所有线程完成倒计时(一个或者多个线程,等待其他多个线程完成某件事情之后才能执行)

  • 其中构造参数用来初始化等待计数值
  • await() 用来等待计数归零
  • countDown() 用来让计数减一

7.控制某个方法允许并发访问线程的数量

Semaphore [ˈsɛməˌfɔr] 信号量,是JUC包下的一个工具类,我们可以通过其限制

执行的线程数量,达到限流的效果当一个线程执行时先通过其方法进行获取许可操作,获取到许可的线程继续执行业务逻辑,当线程执行完成后进行释放许可操作,未获取达到许可的线程进行等待或者直接结束。


Semaphore两个重要的方法


lsemaphore.acquire(): 请求一个信号量,这时候的信号量个数-1(一旦没有可使用的信号量,也即信号量个数变为负数时,再次请求的时候就会阻塞,直到其他线程释放了信号量)


lsemaphore.release():释放一个信号量,此时信号量个数+1

8.谈谈对ThreadLocal的理解

ThreadLocal是多线程中对于解决线程安全的一个操作类,它会为每个线程都分配一个独立的线程副本从而解决了变量并发访问冲突的问题。ThreadLocal 同时实现了线程内的资源共享。

ThreadLocal基本使用:

  • set(value) 设置值
  • get() 获取值
  • remove() 清除值

实现原理:

ThreadLocal本质来说就是一个线程内部存储类,从而让多个线程只操作自己内部的值,从而实现线程数据隔离。在ThreadLocal中有一个内部类叫做ThreadLocalMap,类似于HashMap。ThreadLocalMap中有一个属性table数组,这个是真正存储数据的位置。


ThreadLocal内存泄漏:


Java对象中的四种引用类型:强引用、软引用、弱引用、虚引用


强引用:最为普通的引用方式,表示一个对象处于有用且必须的状态,如果一个对象具有强引用,则GC并不会回收它。即便堆中内存不足了,宁可出现OOM,也不会对其进行回收


  • 弱引用:表示一个对象处于可能有用且非必须的状态。在GC线程扫描内存区域时,一旦发现弱引用,就会回收到弱引用相关联的对象。对于弱引用的回收,无关内存区域是否足够,一旦发现则会被回收

每一个Thread维护一个ThreadLocalMap,在ThreadLocalMap中的Entry对象继承了WeakReference。其中key为使用弱引用的ThreadLocal实例,value为线程变量的副本

相关文章
|
4月前
|
设计模式 运维 监控
并发设计模式实战系列(4):线程池
需要建立持续的性能剖析(Profiling)和调优机制。通过以上十二个维度的系统化扩展,构建了一个从。设置合理队列容量/拒绝策略。动态扩容/优化任务处理速度。检查线程栈定位热点代码。调整最大用户进程数限制。CPU占用率100%
304 0
|
弹性计算 运维 数据挖掘
DDD与微服务架构浅析
主要介绍DDD,微服务架构,以及两者之间的关系
DDD与微服务架构浅析
|
6月前
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestBody
`@RequestBody` 是 Spring 框架中的注解,用于将 HTTP 请求体中的 JSON 数据自动映射为 Java 对象。例如,前端通过 POST 请求发送包含 `username` 和 `password` 的 JSON 数据,后端可通过带有 `@RequestBody` 注解的方法参数接收并处理。此注解适用于传递复杂对象的场景,简化了数据解析过程。与表单提交不同,它主要用于接收 JSON 格式的实体数据。
480 0
|
7月前
|
存储 缓存 Java
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
741 3
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
|
8月前
|
JSON 人工智能 JavaScript
大语言模型下的JSON数据格式交互
本文作者总结了在解析JSON过程中遇到的一些问题和解决方案。
|
XML 移动开发 前端开发
JS设置Ajax为同步或异步
JS设置Ajax为同步或异步
310 0
|
10月前
|
Java 数据格式
Java“EOFException”解决
Java中的“EOFException”通常在读取文件或网络流时遇到意外的文件结束符时抛出。解决方法包括检查输入源是否为空、确保数据格式正确以及增加异常处理逻辑。
974 3
|
存储 监控 Java
微服务技术系列教程(42)- SpringCloud -Sleuth与Zipkin服务链路
微服务技术系列教程(42)- SpringCloud -Sleuth与Zipkin服务链路
265 0
|
存储 机器学习/深度学习 运维
Elasticsearch 集群节点的角色与职责
【8月更文挑战第25天】
383 6