线程池 JMM 内存模型

线程池 & JMM 内存模型

文章目录

  • 线程池 & JMM 内存模型
  • 线程池
    • 线程池的创建
    • ThreadPoolExecutor 七大参数
    • 饱和策略
    • ExecutorService 提交线程任务对象执行的方法:
    • ExecutorService 关闭线程池的方法:
    • 线程池最大线程数如何确定?
  • volatile - 多线程之间共享变量的可见性
  • JMM 内存模型
    • 八种操作
    • JMM 对这八种指令的使用,制定了如下规则:

线程池

使用线程池可以实现线程的复用,减少频繁创建和销毁线程对象造成的资源消耗。

好处

  1. 降低资源消耗:减少了创建和销毁线程的次数;

  2. 提高响应速度:不需要频繁的创建线程;

  3. 提高线程的可管理性:线程池可以约束系统中最多的线程数;

线程池的创建

java.util.concurrent.Executors 提供了一系列静态方法创建线程池对象,线程池在 Java 中表现为 ExecutorService 接口。

  1. 使用 ThreadPoolExecutor 构造方法;

  2. 使用 Executor 框架的⼯具类 Executors:实际也是调用了 ThreadPoolExecutor 构造方法,阿里巴巴开发手册强烈不允许使用该种方式

  • FixedThreadPool : 该方法返回⼀个固定线程数量的线程池。该线程池中的线程数量始终不变。当有⼀个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在⼀个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
  • SingleThreadExecutor: 方法返回⼀个只有⼀个线程的线程池。若多余⼀个任务被提交到该线程池,任务会被保存在⼀个任务队列中,待线程空闲,按先入先出的顺序执⾏队列中的任务。
  • CachedThreadPool: 该方法返回⼀个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复⽤,则会优先使用可复⽤的线程。若所有线程均在⼯作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复⽤。

推荐创建线程池方式:ThreadPoolExecutor

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, // 核心线程数5, // 最大线程数,超出阻塞队列时才会触发最大线程数3, // 超出核心线程数时,终止空闲线程的等待时间TimeUnit.SECONDS, // 时间单位new LinkedBlockingQueue<Runnable>(3), // 阻塞队列Executors.defaultThreadFactory(), // 默认创建线程工厂new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);

ThreadPoolExecutor 七大参数

  1. corePoolSize:核心线程数,保留在线程池中的线程数,即使它们处于空闲状态,除非设置了allowCoreThreadTimeOut

  2. maximumPoolSize:最大线程数,当工作队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最⼤线程数;

  3. keepAliveTime:当线程数大于核心线程数时,这是多余空闲线程在终止前等待新任务的最长时间;

  4. unit:keepAliveTime 参数的时间单位;

  5. workQueue:工作队列,超出核心线程数的任务会保存在任务队列, 这个队列将只保存 execute 方法提交的 Runnable任务;

  6. threadFactory:执行程序创建新线程时使用的工厂;

  7. handler:饱和策略(拒绝策略),执行被阻塞时使用的处理程序,因为达到了线程边界和队列容量;

饱和策略

  1. ThreadPoolExecutor.AbortPolicy :抛出 RejectedExecutionException 来拒绝新任务的处理。

  2. ThreadPoolExecutor.CallerRunsPolicy :调用执行自己的线程运行任务(使用提交该任务的线程执行)。您不会任务请求。但是这种策略会降低对于新任务提交速度,影响程序的整体性能。另外,这个策略喜欢增加队列容量。如果您的应⽤程序可以承受此延迟并且你不能任务丢弃任何⼀个任务请求的话,你可以选择这个策略。

  3. ThreadPoolExecutor.DiscardPolicy : 不处理新任务,直接丢弃掉。

  4. ThreadPoolExecutor.DiscardOldestPolicy : 此策略将丢弃最早的未处理的任务请求。

ExecutorService 提交线程任务对象执行的方法:

  1. Future<?> submit(Runnable task):提交一个 Runnable 的任务对象给线程池执行;

  2. Future<?> submit(Callable task):提交一个 Callable 的任务对象给线程池执行,可以通过 get() 得到返回结果。

  3. public void execute(Runnable command):不返回结果使用 execute;

ExecutorService 关闭线程池的方法:

  1. shutdown():等待任务执行完毕以后才会关闭线程池;

  2. shutdownNow():立即关闭线程池的代码,无论任务是否执行完毕,相当于给每个线程调用了 intercept() 方法。

线程池提交线程任务对象会自动启动线程执行。

ExecutorService pools = Executors.newFixedThreadPool(3);// 实现 Callable 接口
Future<String> result= pools.submit((Callable<String>) () -> {});
// 获取线程执行返回的结果
String r = result.get()// 实现 Runnable 接口
pools.submit(() -> {});

线程池最大线程数如何确定?

  1. CPU 密集型:定义为机器 CPU 核数,Runtime.getRuntime().availableProcessors()

  2. IO 密集型:定义为 IO 密集线程的 2 倍;

线程池主要执行流程

在这里插入图片描述

volatile - 多线程之间共享变量的可见性

引入:A 线程修改了共享变量的值,但是在主线程中读取到的还是之前的值,修改后的值无法读取到。

解释:根据 JMM 内存模型,线程在本地内存中会有共享变量的副本,A 线程修改了其本地内存的变量更新到主内存中,当主线程操作共享变量时,还是读取的主线程中本地内存的共享变量副本,此时还没有跟主内存共享变量同步,导致无法读取到修改后的值,这个现象称为线程之间共享变量的不可见性。

解决方案

  1. 加锁:

​ a. 线程获得锁;

​ b. 清空本地工作内存;

​ c. 从主内存中拷贝最新值到工作内存;

  1. 使用 volatile 关键字修饰共享变量:使用 volatile 关键字修饰的变量被修改后,主内存更新后会将其他线程本地工作内存中的变量副本失效,重新读取主内存的最新值,从而保证了可见性。

区别:volatile 关键字不保证原子性。

volatile 是 Java 虚拟机提供轻量级的同步机制

特点:

  1. 保证可见性

  2. 不保证原子性

  3. 禁止指令重排

JMM 内存模型

在这里插入图片描述

JMM (Java Memory Model),Java 内存模型。是 Java 虚拟机规范中所定义的一种内存模型。 Java 内存模型(Java Memory Model)描述了 Java 程序中各种变量(线程共享变量)的访问规则,以及在 JVM 中将变量存储到内存和从内存中读取变量这样的底层细节。 所有的共享变量都存储于主内存。这里所说的变量指的是实例变量和类变量。不包含局部变量,因为局部变量是线程私有的,因此不存在竞争问题。每一个线程还存在自己的工作内存,线程的工作内存,保留了被线程使用的变量的工作副本。线程对变量的所有的操作(读,取)都必须在工作内存中完成,而不能直接读写主内存中的变量,不同线程之间也不能直接访问对方工作内存中的变量,线程间变量的值的传递需要通过主内存完成。

八种操作

内存交互操作有 8 种,虚拟机实现必须保证每一个操作都是原子的,不可在分的(对于double和long类型的变量来说,load、store、read 和 write 操作在某些平台上允许例外)

  1. lock (锁定):作用于主内存的变量,把一个变量标识为线程独占状态;

  2. unlock (解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定;

  3. read (读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的 load动作使用;

  4. load (载入):作用于工作内存的变量,它把 read 操作从主存中变量放入工作内存中;

  5. use (使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个指令;

  6. assign (赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中

  7. store (存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,以便后续的 write 使用

  8. write (写入):作用于主内存中的变量,它把 store 操作从工作内存中得到的变量的值放入主内存的变量中

JMM 对这八种指令的使用,制定了如下规则:

  1. 不允许 read 和 load、store 和 write 操作之一单独出现。即使用了read 必须 load,使用了store 必须 write

  2. 不允许线程丢弃他最近的 assign 操作,即工作变量的数据改变了之后,必须告知主存

  3. 不允许一个线程将没有 assign 的数据从工作内存同步回主内存

  4. 一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量实施 use、store 操作之前,必须经过 assign 和 load 操作

  5. 一个变量同一时间只有一个线程能对其进行 lock。多次 lock 后,必须执行相同次数的 unlock 才能解锁

  6. 如果对一个变量进行 lock 操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重新load 或 assign 操作初始化变量的值

  7. 如果一个变量没有被 lock,就不能对其进行 unlock 操作。也不能 unlock 一个被其他线程锁住的变量

  8. 对一个变量进行 unlock 操作之前,必须把此变量同步回主内存

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[论文阅读] 软件工程 + 教学 | 软件工程项目管理课程改革:从传统教学到以学生为中心的混合式学习实践

软件工程项目管理课程改革&#xff1a;从传统教学到以学生为中心的混合式学习实践 论文信息 arXiv:2506.14369 Agile and Student-Centred Teaching of Agile/Scrum Concepts Maria Spichkova Comments: Preprint. Accepted to the 29th International Conference on Knowledg…

Windows系统提示“mfc140u.dll丢失”?详细修复指南,一键恢复程序运行!

当你兴致勃勃地打开某个游戏或专业软件时&#xff0c;突然弹出一条错误提示——“MFC140u.dll丢失”&#xff0c;程序直接闪退&#xff0c;让人无比沮丧。别担心&#xff01;这个问题并不复杂&#xff0c;通常只需重新安装运行库或修复系统文件即可解决。本文将为你提供详细的修…

云XR(AR/VR)算力底座关键特征与技术路径

云XR&#xff08;AR/VR&#xff09;算力底座是支撑扩展现实技术规模化落地的核心基础设施&#xff0c;当前发展呈现以下关键特征与技术路径&#xff1a; 一、算力架构&#xff1a;云边端协同异构融合 分布式部署模式‌ 云端‌&#xff1a;承担高复杂度渲染与大数据处理&#x…

Android开发常用adb合集

Android开发常用adb合集 Android开发常用adb合集crash日志导出 Android开发常用adb合集 crash日志导出 bugreport: adb bugreportdropbox: adb shell dumpsys dropbox --print > desktop/full_dropbox_logs.txt

LTspice仿真4——exp指数函数波形

参数设置 Vinitial&#xff1a;初始电压值 Vpulsed&#xff1a;脉冲达到值 Rise Delay&#xff1a;上升延迟时间 Rise Tau&#xff1a;上升指数系数tau Fall Delay&#xff1a;下降延迟时间 Fall Tau&#xff1a;下降指数系数tau tau决定指数波形下降或者上升快慢&#x…

[Java 基础]集合框架

在 Java 中&#xff0c;我们经常需要存储和操作一组数据&#xff0c;而集合框架就是为此而生。它提供了一套统一的接口和类&#xff0c;帮助我们高效地管理各种数据集合。 常用的集合框架中的类只有 ArrayList、LinkedList、HashSet、HashMap 这 4 个&#xff0c;这些类的继承…

SQL关键字三分钟入门:WITH —— 公用表表达式让复杂查询更清晰

在实际的数据库开发和分析中&#xff0c;我们常常会遇到复杂的多层嵌套查询&#xff0c;这样的 SQL 语句不仅难以阅读&#xff0c;也容易出错。 这时候就需要使用一个非常实用又优雅的关键字 —— WITH&#xff01; 它可以帮助我们将复杂的子查询提取出来并命名&#xff0c;从…

要在 Linux 不联网服务器 上部署并运行 Gitee 上的 vue-vben-admin 项目,并且该项目使用的是 pnpm 管理依赖

目录 ✅ 目标&#xff1a;在不联网服务器中成功运行 vue-vben-admin &#x1f449; 你需要的最终环境&#xff1a; ✅ 场景&#xff1a;完全离线部署并运行开发/构建环境 &#x1f9f1; 步骤总览&#xff1a; &#x1f6e0; 详细操作流程 ✅ 第 1 步&#xff1a;联网机器准…

中国风国潮通用PPT模版

中国风答辩总结汇报类通用PPT模版&#xff0c;古风PPT通用模版&#xff0c;国学精品PPT模版&#xff0c;中国风韵PPT模版 中国风国潮通用PPT模版&#xff1a;https://pan.quark.cn/s/59cea717fe8d

【nvidia-H100-ib排障实战2】:服务器 InfiniBand 网络性能问题深度分析

目录 InfiniBand 网络性能日志: 实际生产服务器 InfiniBand 网络性能问题深度分析 一、核心问题定位:mlx5_1 设备性能异常 二、问题详细分析 1. mlx5_1 设备异常原因推测 (1)硬件连接故障 (2)驱动或固件问题 (3)资源争用或配置错误 2. CPU 频率不一致问题 三…

Postgresql中不同数据类型的长度限制

目录 一、字符类型&#xff08;Character Types&#xff09; 二、二进制类型&#xff08;Binary Types&#xff09; 三、数值类型&#xff08;Numeric Types&#xff09; 四、其他类型 五、全局限制&#xff1a;单行数据总大小 示例对比表 注意事项 验证命令 在 Postgr…

Unity Hub 新建项目,启动 Unity 闪退的解决办法

问题&#xff1a; Win11: Unity 闪退&#xff0c;提示 Could not connect project 原因 这是 Firewall & network protection 在作怪&#xff0c;真的我感觉 Windows Defender 就从来没干过好事&#xff0c;那个遍地是病毒的年代微软你不搞个杀毒软件&#xff0c;现在…

学习打卡---回溯

回溯&#xff0c;所有回溯都可以转换成树形结构进行解决 我们将树形结构分为纵向和横向两个方面 递归是纵向循环&#xff0c;也就是纵向方面&#xff0c;到了叶子节点就收网回溯 循环是横向循环&#xff0c;也就是横向方面&#xff0c;到了数组末尾就结束 回溯属于是将二叉树的…

阿里云获取DASHSCOPE_API_KEY教程,以及配置DASHSCOPE_API_KEY环境变量

要获取阿里云的 DASHSCOPE_API_KEY&#xff08;通义千问API密钥&#xff09;&#xff0c;需要在阿里云平台上完成开通服务和创建密钥的流程。以下是具体步骤&#xff1a; 1. 开通通义千问API服务 登录阿里云账号 访问 阿里云官网&#xff0c;使用账号密码或RAM用户登录。 进入…

《去哪儿网Redis高并发实战:从问题定位到架构升级》

去哪儿网Redis高并发实战&#xff1a;从问题定位到架构升级 在互联网行业竞争日益激烈的当下&#xff0c;高并发场景下的系统性能优化一直是技术团队面临的重要挑战。对于去哪儿网这类在线旅游平台来说&#xff0c;节假日期间的流量高峰更是对系统架构的严峻考验。本文将深入剖…

Zynq + FreeRTOS + YAFFS2 + SQLite3 集成指南

Zynq FreeRTOS YAFFS2 SQLite3 集成指南 一、系统架构设计 #mermaid-svg-qvuP6slyza89wsiT {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-qvuP6slyza89wsiT .error-icon{fill:#552222;}#mermaid-svg-qvuP6slyz…

设计模式精讲 Day 6:适配器模式(Adapter Pattern)

【设计模式精讲 Day 6】适配器模式&#xff08;Adapter Pattern&#xff09; 文章内容 在“设计模式精讲”系列的第6天&#xff0c;我们将深入讲解适配器模式&#xff08;Adapter Pattern&#xff09;。作为结构型设计模式之一&#xff0c;适配器模式的核心思想是将一个类的接…

系统稳定性治理

一、微服务内部异常 描述 微服务Pod自动重启表现&#xff1a;服务波动&#xff08;响应时间不稳定&#xff09;、监控指标异常&#xff08;Pod重启次数增加&#xff0c;CPU/内存波动&#xff09;、Kubernetes事件记录容器重启原因影响&#xff1a;服务中断、性能波动、资源消耗…

多智能体协同的力量:赋能AI安全报告系统的智能设计之道

“设想一个由‘数据采集者’、‘风险分析师’、‘报告撰写员’甚至‘合规监督员’组成的虚拟团队&#xff0c;它们如何携手打造一份深度洞察、精准预警的危化安全报告&#xff1f;这正是多智能体协作在AI安全领域的魅力所在。” 一、挑战升级&#xff1a;单一AI难以应对的复杂性…

ceph pg 卡在 active+clean+remapped 状态

场景 ceph 环境中有个 osd.0 做了 raid0 ,后来想剔除掉,执行了 ceph osd out 0 然后等了很长时间等 pg 数据迁移到别的 osd,但是最后有一个 pg 状态卡在了 active+clean+remapped 状态。如下: ceph pg ls-by-osd 0 PG OBJECTS DEGRADED MISPLACED UNFOUND BYTES …