线程池
JVM 中的线程与操作系统的线程是一对一的关系,所以在 JVM 中每创建一个线程就需要调用操作系统提供的 API 创建线程,赋予资源,并且销毁线程同样也需要系统调用。
而系统调用就意味着上下文切换等开销,并且线程也是需要占用内存的,而内存也是珍贵的资源。
因此线程的创建和销毁是一个重操作,并且线程本身也占用资源。
然后你还需要知道,线程数并不是越多越好。
我们都知道线程是 CPU 调度的最小单位,在单核时代,如果是纯运算的操作是不需要多线程的,一个线程一直执行运算即可。但如果这个线程正在等待 I/O 操作,此时 CPU 就处于空闲状态,这就浪费了 CPU 的算力,因此有了多线程,在某线程等待 I/O 等操作的时候,另一个线程顶上,充分利用 CPU,提高处理效率。
CPU 的核心数有限,同时能运行的线程数有限,所以需要根据调度算法切换执行的线程,而线程的切换需要开销,比如替换寄存器的内容、高速缓存的失效等等。
<<======>>
- Java中线程与操作系统线程是一比一的关系。
- 线程的创建和销毁是一个“较重”的操作。
- 多线程的主要是为了提高 CPU 的利用率。
- 线程的切换有开销,线程数的多少需要结合 CPU核心数与 I/O 等待占比.
------------->
因为线程数太少无法充分利用 CPU ,太多的话由于上下文切换的消耗又得不偿失,所以我们需要评估系统所要承载的并发量和所执行任务的特性,得出大致需要多少个线程数才能充分利用 CPU,因此需要控制线程数量。
又因为线程的创建和销毁是一个“重”操作,所以我们需要避免线程频繁地创建与销毁,因此我们需要缓存一批线程,让它们时刻准备着执行任务。
目标已经很清晰了,弄一个池子,里面存放约定数量的线程,这就是线程池,一种池化技术。
注释:一般池化技术的使用方式是从池子里拿出资源,然后使用,用完了之后归还;线程池的常见实现更像是一个黑盒存在,我们设置好线程池的大小之后,直接往线程池里面丢任务,然后就不管了。线程池其实是一个典型的生产者-消费者模式。
线程池内部会有一个队列来存储我们提交的任务,而内部线程不断地从队列中索取任务来执行,这就是线程池最原始的执行机制。
线程池把任务的提交和任务的执行剥离开来,当一个任务被提交到线程池之后:
- 如果此时线程数小于核心线程数,那么就会新起一个线程来执行当前的任务。
- 如果此时线程数大于核心线程数,那么就会将任务塞入阻塞队列中,等待被执行。
- 如果阻塞队列满了,并且此时线程数小于最大线程数,那么会创建新线程来执行当前任务。
- 如果阻塞队列满了,并且此时线程数大于最大线程数,那么会采取拒绝策略。
线程池de几种状态:
- RUNNING:能接受新任务,并处理阻塞队列中的任务
- SHUTDOWN:不接受新任务,但是可以处理阻塞队列中的任务
- STOP:不接受新任务,并且不处理阻塞队列中的任务,并且还打断正在运行任务的线程,就是直接撂担子不干了!
- TIDYING:所有任务都终止,并且工作线程也为0,处于关闭之前的状态
- TERMINATED:已关闭。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战