JAVA并发编程系列(11)线程池底层原理架构剖析

面试官:说说JAVA线程池的几个核心参数?

之前我们用了10篇文章详细剖析了synchronized、volatile、CAS、AQS、ReentrantLock、Semaphore、CountDownLatch、CyclicBarrier、并发锁、Condition等各个核心基础原理,今天开始我们说说并发领域的各种工具包还有应用场景。

1、为什么要用线程池?

日常频繁创建和销毁线程是非常消耗系统资源的操作,会降低系统的整体性能。而线程池通过池化的管理思想,把线程的创建、任务调度、任务执行、任务等待、任务拒绝、销毁等全生命周期各个环节都进行统一管理,大幅提升系统性能,提高线程利用率以及任务响应。

2、线程池核心参数意义

一共有6个:

    private volatile ThreadFactory threadFactory;private volatile RejectedExecutionHandler handler;private volatile long keepAliveTime;//非核心线程空闲超时时间private volatile boolean allowCoreThreadTimeOut;private volatile int corePoolSize;//核心线程数量private volatile int maximumPoolSize;//最大线程数量
2.1 corePoolSize 核心线程数量

核心线程即使空闲,也不会被回收。如果当前线程数量小于corePoolSize,即使其他核心线程空闲,线程池也会新增创建一个线程来执行任务。

核心线程会一直存活在线程池里,但是如何设置了线程池的allowCoreThreadTimeOut为true,则核心线程空闲一定时间也会被回收。

private volatile boolean allowCoreThreadTimeOut

2.2 maximumPoolSize最大线程数量

线程池最大线程数量maximumPoolSize = 核心线程数量corePoolSize + 非核心线程数量。

场景A:当线程数量>=核心线程数量,且等待队列未满,将任务加入到等待队列。

场景B:当队列已满,并且线程数量<maximumPoolSize ,就新增非核心线程。这种非核心线程就是在空闲时间大于keepAliveTime,就会被回收。

场景C:当队列已满,且线程数量大于等于maximumPoolSize,就触发拒绝策略handler拒绝任务。

2.3 keepAliveTime 线程空闲时间

keepAliveTime允许线程的最大的空闲存活时间。如果一个非核心线程在空闲状态下持续超过keepAliveTime了,就会被回收,以及线程池设置allowCoreThreadTimeOut为true,核心线程也会被回收。

2.4 workQueue任务存储队列

用于存储等待执行的任务。主要有三种类型。

第一个,直接提交SynchronousQueue,把任务直接提交给工作线程而不放到等待队列。这个队列不存储元素,newCachedThreadPool使用的就是这种同步移交队列,吞吐量比LinkedBlockingQueue大。

第二个,LinkedBlockingQueue无界队列,队列的最多容量为int的最大值,相当于无限容量。newFixedThreadPool和newSingleThreadPool使用的就是LinkedBlockingQueue,这个吞吐量比ArrayBlockingQueue高。

第三个,ArrayBlockingQueue有界队列,可以有效避免资源耗尽。

除了这三种,还有DelayQueue、PriorityBlockingQueue。

2.5 threadFactory线程工厂

线程工厂,用来创建线程。

2.6 handler拒绝策略

拒绝任务的策略。当线程数量达到最大线程数量maximumPoolSize,以及等待队列workQueue也满了,这时候需要用来拒绝任务提交时的策略handler。策略类型有抛异常、用调用者所在的线程执行任务、丢弃队列中第一个任务执行当前任务、直接丢弃任务)。

策略种类有:

AbortPolicy:直接抛出异常。

DiscardPolicy:丢弃任务,不抛异常。

DiscardOldestPolicy:将等待队列里等待最久的任务丢弃。

CallerRunsPolicy: 哪个线程提交的任务,哪个线程去处理。

4、有几种线程池?

JAVA线程池ThreadPoolExcutor,常见的有这四种线程池。

//初始化一个无限线程的线程池,无需等待队列
Executors.newCachedThreadPool()
//初始化一个支持周期性运行的线程池
Executors.newScheduledThreadPool(10);
//初始化固定数目线程的线程池
Executors.newFixedThreadPool(10);
//初始化仅有一个线程的线程池
Executors.newSingleThreadExecutor();
4.1 Executors.newCachedThreadPool()可缓存线程池

创建一个可缓存的线程池,如果线程数量大于处理任务时,空闲线程被回收;当提交任务增加时,又可以新建线程去处理任务。这种线程池的线程数无限制,corePoolSize数值为0, maximumPoolSize 的数值都是为 Integer.MAX_VALUE。

线程可复用性很高,可以减少频繁创建/销毁线程,减少系统开销。工作队列workQueue选用SynchronousQueue。

4.2 Executors.newScheduledThreadPool()定时调度线程池

也是固定长度的线程池,但是支持以延迟或者定时的方式去执行任务。

4.3 newSingleThreadExecutor()单线程的线程池

一个线程,corePoolSize 和 maximumPoolSize 的数值都是为 1,线程池里只有一个工作线程执行任务。若这个唯一的线程异常出问题了,会新建另一个线程来替代。所有任务在等待队列是FIFO顺序被执行。

4.4 Executors.newFixedThreadPool()固定长度线程池

每次提交任务的时候就会创建一个新的线程,直到达到线程池的最大数量限制,如何任务大于线程数量,就进入等待队列。 corePoolSize 和 maximumPoolSize 的数值相等。工作队列选用LinkedBlockingQueue。

最后,我们上一个线程池demo,固定线程池,每次最多N个线程在执行任务,其他任务等待。

package lading.java.mutithread;import cn.hutool.core.date.DateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;/*** 固定线程池,线程数量为3* 提交多个count+1任务计算**/
public class Demo013ThreadPool {//计算任务countpublic static AtomicInteger count = new AtomicInteger(0);public static void main(String[] args) {//固定数量线程池ExecutorService service = Executors.newFixedThreadPool(3);Executors.newScheduledThreadPool(10);//提交20次,对count+1的任务for (int i = 1; i < 20 + 1; i++) {service.submit(new Thread(() -> {//模拟每次计算耗时2stry {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}//完成本次对count+1计算任务System.out.println(DateTime.now().toString("YYYY-MM-dd hh:mm:ss") + " " +Thread.currentThread().getName() + "线程 执行计算任务:" + count.incrementAndGet());}));}service.shutdown();}
}

每次只有三个线程在运行任务,其他任务等之前任务执行完成后再执行。

今天就分享到这,明天分享并发容器CurrentHashMap。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/149175.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGLM-6B:部署指南与实战应用全解析

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 SD3ComfyUI文生图部署步骤DAMODEL-ChatGLM-6B 服务端部署1.1、实例创建1.2、模型准备1.3、模型启动 SD3ComfyUI文生图部署步骤 Chat…

Redis6.0.9配置redis集群

写在前面 最近在完成暑期大作业&#xff0c;期间要将项目部署在云服务器上&#xff0c;其中需要进行缓存的配置&#xff0c;决定使用Redis&#xff0c;为了使系统更加健壮&#xff0c;选择配置Redis-Cluster。由于服务器资源有限&#xff0c;在一台服务器上运行6个Redis Instan…

pnpm : 无法加载文件

1、以管理员身份运行window powershell 2、执行Get-ExecutionPolicy&#xff0c;显示Restricted 3、执行set-ExecutionPolicy&#xff0c;会提示输入参数&#xff0c;此时输入RemoteSigned回车 4、执行y回车

想把泰文从文本上识别,什么软件工具好用呢?

泰文识别技术涉及将泰文图像转换成数字文本&#xff0c;主要通过光学字符识别&#xff08;OCR&#xff09;技术实现。这项技术广泛应用于文档处理、语言学习和翻译服务。实现泰文识别的方法包括使用手机应用程序、在线服务、专业软件&#xff0c;以及结合人工智能和机器学习。此…

【Docker】如何让docker容器正常使用nvidia显卡

首先确保宿主机正常安装了显卡驱动 nvidia-smi打印显卡信息如下&#xff1a; 安装nvidia-container-toolkit工具 sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit sudo systemctl restart docker运行如下命令测试显卡是否在容器内可用 …

Arduino中使用库文件读取陀螺仪MPU6050欧拉角

目录 1、库文件安装 &#xff08;1&#xff09;方法1-网上下载库文件 &#xff08;2&#xff09;方法2-本地库文件夹中添加 2、欧拉角获取 &#xff08;1&#xff09;打开测试程序 &#xff08;2&#xff09;读欧拉角程序 &#xff08;3&#xff09;坐标系和欧拉角说明 …

征才令!开物™创新论文激励计划,等你来大展身手

背景介绍 随着云计算、人工智能的迅猛发展&#xff0c;现有的IT系统变得日益复杂&#xff0c;网络技术亟需创新才能满足现代数据中心、智算中心的网络需求。在这一背景下&#xff0c;被定义为“未来数据中心第三颗主力芯片”的DPU崭露头角&#xff0c;成为未来网络技术的发展方…

iOS V2签名网站系统源码 开源免授权

简介 这是一款iOS 签名站的开源源码&#xff0c;免去了授权&#xff0c;它支持UDID获取、软件选择以及签名码功能。 同时&#xff0c;用户可以多开APP进行安装。这是一个自主可下载的版本&#xff0c;感兴趣的用户可以自行获取。 界面

aws s3 存储桶 前端组件上传简单案例

写一个vue3 上传aws oss存储的案例 使用到的插件 npm install aws-sdk/client-s3 注意事项 &#xff1a; 1. 本地调试 &#xff0c; 需要设置在官网设置跨域 必须&#xff01;&#xff01;&#xff01; 否则调试不了 &#xff0c;前端代理是不起作用的 &#xff0c;因为是插…

【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c;你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能够帮助到你&#xff01; 目录 一&#xff1a;单例模式&#xff08;singleton&#xff09; 1&#xff1a;概念 二&#xff1a;“饿汉模…

JavaEE——多线程Thread 类及常见方法

目录 一、Thread(String name) 二、是否后台线程 isDeamon() 三、是否存活 isAlive() 四、run()方法和start()方法的区别 五、中断线程 法一&#xff1a; 法二&#xff1a; 六、线程等待join() 七、线程休眠sleep() 一、Thread(String name) 定义&#xff1a;这个东西…

期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟

在 AI 程序员的帮助下&#xff0c;一个几乎没有专业编程经验的初中生&#xff0c;在人头攒动的展台上从零开始&#xff0c;两分钟就做出了一个倒计时网页。 他需要做的&#xff0c;只是输入包含几句话的提示词。数秒钟后&#xff0c;大模型就生成了代码&#xff0c;还列出了环…

​地质图制图规范大全资料分享

我们在《2024年最新测绘地理信息规范在线查看下载》一文整理460个测绘地理信息相关规范的在线查看链接。 现在我们又整理了地质图制图规范大全分享给大家&#xff0c;你可以在文末查看该文档的领取方法。 地质图制图规范大全 这些地质图制图规范来自地质科学数据出版系统&am…

基于 IV 的因果中介分析模型及 Stata 实现

目录 一、文献综述 二、理论原理 三、实证模型 四、稳健性检验 五、程序代码及解释 一、文献综述 因果中介分析在众多学科领域中都占据着关键地位&#xff0c;其重要性日益凸显。在社会科学领域&#xff0c;如经济学和社会学中&#xff0c;研究者们常常致力于揭示各种因素之…

深度学习实战:UNet模型的训练与测试详解

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 1、云实例&#xff1a;配置选型与启动1.1 登录注册1.2 配置 SSH 密钥对1.3 创建实例1.4 登录云实例 2、云存储&#xff1a;数据集上传…

vue2 搜索高亮关键字

界面&#xff1a; 搜索 “成功” 附上代码&#xff08;开箱即用&#xff09; <template><div class"box"><input class"input-box" v-model"searchKeyword" placeholder"输入搜索关键字" /><div class"r…

tauri开发软件中,使用tauri自带的api用浏览器打开指定的url链接

有能力的可以看官方文档&#xff1a;shell | Tauri Apps 就是使用这个api来打开指定的url链接&#xff0c;要在tauri.config.json中配置打开这个api&#xff1a; 然后在前端页面中导入使用&#xff1a; import { open } from tauri-apps/api/shell; // opens the given URL o…

年轻用户对Facebook的使用趋势分析

在社交媒体的蓬勃发展中&#xff0c;Facebook作为全球最大的社交平台之一&#xff0c;尽管面临着来自新兴平台的竞争&#xff0c;仍然在年轻用户中扮演着重要角色。然而&#xff0c;年轻用户对Facebook的使用方式和趋势却在不断变化。本文将探讨年轻用户对Facebook的使用趋势&a…

代码随想录算法训练营Day14 | 226.翻转二叉树、101. 对称二叉树、104.二叉树的最大深度、111.二叉树的最小深度

目录 226.翻转二叉树 101. 对称二叉树 104.二叉树的最大深度 111.二叉树的最小深度 226.翻转二叉树 题目 226. 翻转二叉树 - 力扣&#xff08;LeetCode&#xff09; 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例1&#…

Redis 篇-深入了解 Redis 五种数据类型和底层数据结构(SDS、Intset、Dict、ZipList、SkipList、QuickList)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 Redis 底层数据结构 1.1 Redis 数据结构 - 动态字符串 SDS 1.2 Redis 数据结构 - Intset 1.3 Redis 数据结构 - Dict 1.3.1 Dict 的渐进式 rehash 1.4 Redis 数据…