多线程进阶核心知识详解(通俗版)
Java多线程进阶详解
一、锁策略:如何高效管理资源竞争
在多线程环境中,锁是协调资源访问的核心机制。不同的锁策略适用于不同的场景,理解它们的差异能帮助优化程序性能。
1. 乐观锁 vs 悲观锁
-
悲观锁:
-
核心思想:假设每次访问资源都会发生冲突,因此每次操作前先加锁。
-
类比:去图书馆借书时,管理员每次都锁上书柜,借阅者需排队等待钥匙。
-
实现:
synchronized
在竞争激烈时转为悲观锁,依赖操作系统的互斥锁(mutex)。 -
适用场景:写操作频繁,如银行转账、库存扣减。
-
-
乐观锁:
-
核心思想:假设冲突概率低,先操作再检查冲突。
-
类比:多人编辑在线文档,直接修改内容,提交时检测版本是否冲突。
-
实现:通过版本号或CAS(Compare and Swap)实现。
-
// 数据库乐观锁示例(伪SQL)
UPDATE products SET stock = stock - 1, version = version + 1
WHERE id = 100 AND version = current_version;
-
适用场景:读多写少,如点赞、评论计数。
2. 自旋锁 vs 挂起等待锁
-
自旋锁:
像追女神,每天发消息问“在吗?”,直到她分手。 -
原理:线程通过循环不断尝试获取锁,而非立即挂起。
-
优点:响应快,避免线程切换开销。
-
缺点:CPU空转,适合锁持有时间短的场景。
-
挂起等待锁:
被拒绝后默默等待,直到女神主动联系。 -
原理:线程获取锁失败后进入阻塞状态,等待被唤醒。
-
优点:节省CPU资源。
-
缺点:线程切换开销大,响应延迟。
-
实现:
synchronized
在竞争激烈时升级为重量级锁,依赖操作系统调度。
3. 公平锁 vs 非公平锁
-
公平锁:按请求顺序分配锁,避免线程饥饿。
-
实现:
ReentrantLock(true)
。 -
适用场景:需要严格顺序的业务,如排队系统。
-
-
非公平锁:允许插队,提高吞吐量。
-
实现:
synchronized
和默认的ReentrantLock
。 -
适用场景:高并发且任务执行时间差异大,如Web服务器。
-
4. 可重入锁(递归锁)
-
核心:同一线程可重复获取同一把锁,避免死锁。
-
实现:
synchronized
和ReentrantLock
。 -
示例:递归方法中的加锁操作。
-
二、CAS机制:无锁编程的魔法
CAS原理
-
三步操作:
-
读取内存值V。
-
比较V与预期值A。
-
若相等,将新值B写入V;否则重试。
-
1. 什么是CAS?
CAS = 检查并交换。就像自动售货机:
boolean CAS(当前值, 预期值, 新值) {if (当前值 == 预期值) {当前值 = 新值;return true;}return false;
}
2. 原子类实现原理
以AtomicInteger
为例:
// 伪代码实现i++
public int getAndIncrement() {int oldValue = value;while (!CAS(value, oldValue, oldValue+1)) {oldValue = value; // 值被改了,重试}return oldValue;
}
3. ABA问题与解决
:线程1读取值A,线程2将A→B→A,线程1的CAS操作误判无变化。
-
问题:你看到瓶子里的水还是满的,但其实已经被倒掉又装满了。
-
解决:加版本号,修改时检查值和版本号是否一致。
-
Java工具:
AtomicStampedReference
AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);
ref.compareAndSet(100, 200, 0, 1); // 检查值和版本号
三、synchronized的锁升级机制
JVM为优化synchronized
性能,设计了锁状态升级策略:
1. 无锁 → 偏向锁
-
场景:单线程访问,无竞争。
-
实现:在对象头记录线程ID,减少加锁开销。
-
类比:办公室的咖啡机默认归你使用,无需每次申请。
2. 偏向锁 → 轻量级锁
-
场景:多个线程交替访问,竞争较低。
-
实现:通过CAS自旋尝试获取锁,失败少量次后升级。
-
代码示例:
synchronized (obj) {// 轻量级锁通过CAS竞争 }
3. 轻量级锁 → 重量级锁
-
场景:高并发竞争,自旋消耗过多CPU。
-
实现:依赖操作系统的互斥锁(mutex),线程挂起等待。
-
缺点:用户态与内核态切换开销大。
4. 其他优化
-
锁消除:JVM检测到不可能存在竞争的锁,直接移除。
public String concat(String s1, String s2) {StringBuffer sb = new StringBuffer(); // 单线程下锁被消除sb.append(s1);sb.append(s2);return sb.toString(); }
锁粗化:合并多个相邻锁操作,减少加锁次数。
-
// 优化前 synchronized (obj) { doA(); } synchronized (obj) { doB(); } // 优化后 synchronized (obj) { doA(); doB(); }
四、JUC工具类:灵活控制并发
Java并发包(JUC)提供多种工具类,解决复杂并发问题。
1. ReentrantLock
-
核心功能:
-
可中断锁:
lockInterruptibly()
-
超时获取锁:
tryLock(long timeout, TimeUnit unit)
-
公平锁:
new ReentrantLock(true)
-
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {// 临界区代码
} finally {lock.unlock();
}
2. Semaphore(信号量)
-
作用:控制同时访问资源的线程数。
-
场景:数据库连接池限流。
-
示例:
-
Semaphore semaphore = new Semaphore(5); // 允许5个线程同时访问 semaphore.acquire(); // 获取许可 try {// 使用资源 } finally {semaphore.release(); // 释放许可 }
3. CountDownLatch(倒计时门闩)
-
作用:等待多个线程完成任务。
-
场景:启动服务前等待所有组件初始化完成。
-
示例:
-
CountDownLatch latch = new CountDownLatch(3); // 线程1、2、3分别执行任务后调用 latch.countDown(); latch.await(); // 主线程等待所有任务完成
4. CyclicBarrier(循环栅栏)
-
作用:多个线程相互等待,达到屏障后同时继续。
-
场景:多阶段任务并行处理。
-
示例:
-
CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有线程到达屏障")); // 每个线程调用 barrier.await();
五、线程池:高效管理线程资源
线程池通过复用线程减少创建销毁开销,提升系统性能。
1. 核心参数
-
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, // 核心线程数(常驻)maximumPoolSize, // 最大线程数(核心+临时)keepAliveTime, // 临时线程空闲存活时间TimeUnit, // 时间单位workQueue, // 任务队列(如LinkedBlockingQueue)threadFactory, // 线程创建工厂rejectedExecutionHandler // 拒绝策略 );
2. 工作流程
-
提交任务,优先由核心线程执行。
-
核心线程满 → 任务入队列。
-
队列满 → 创建临时线程。
-
达到最大线程数 → 触发拒绝策略。
3. 拒绝策略
-
AbortPolicy:抛出
RejectedExecutionException
(默认)。 -
CallerRunsPolicy:由提交任务的线程执行。
-
DiscardOldestPolicy:丢弃队列中最老的任务。
-
DiscardPolicy:静默丢弃新任务。
4. 创建线程池的四种方式
// 固定线程数
ExecutorService fixedPool = Executors.newFixedThreadPool(10);
// 弹性线程数(无界队列)
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 单线程(任务顺序执行)
ExecutorService singlePool = Executors.newSingleThreadExecutor();
// 定时任务
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(5);
六、线程安全集合类
1. ConcurrentHashMap
-
Java7分段锁:将数据分为16段,每段独立加锁。
-
Java8优化:
-
每个桶独立加锁(链表头节点作为锁对象)。
-
链表长度≥8时转为红黑树,提高查询效率。
-
-
对比Hashtable:
特性 Hashtable ConcurrentHashMap 锁粒度 全表锁 桶级锁 并发性能 低 高 扩容机制 单线程扩容 多线程协同扩容
2. CopyOnWriteArrayList
-
原理:写操作时复制新数组,保证读操作无锁。
-
适用场景:读多写少(如监听器列表)。
-
代码示例:
-
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); list.add("item"); // 写时复制
七、死锁与解决方案
1. 死锁产生的四个条件
-
互斥:资源只能被一个线程占用。
-
不可抢占:资源只能由持有者释放。
-
请求保持:线程持有资源并等待其他资源。
-
循环等待:多个线程形成环形等待链。
2. 避免死锁的方法
-
统一加锁顺序:所有线程按固定顺序获取锁。
// 错误示例:线程1锁A→锁B,线程2锁B→锁A(可能死锁)
// 正确示例:所有线程按A→B顺序加锁
synchronized (lockA) {synchronized (lockB) { /* ... */ }
}
超时机制:使用tryLock
设置超时时间。
if (lock.tryLock(1, TimeUnit.SECONDS)) {try { /* ... */ } finally { lock.unlock(); }
}
3. 死锁检测与恢复
-
工具:使用
jstack
或JConsole分析线程转储。 -
恢复:强制终止线程或回滚操作(复杂且少用)。
总结
多线程编程的核心在于合理管理资源竞争与线程协作。关键点包括:
-
锁策略选择:根据场景选择乐观锁、悲观锁、公平锁等。
-
CAS无锁编程:通过原子类避免锁开销,注意ABA问题。
-
线程池优化:合理配置参数,平衡资源利用与响应速度。
-
安全集合:优先使用
ConcurrentHashMap
和CopyOnWriteArrayList
。 -
死锁预防:统一加锁顺序,使用超时机制。
通过深入理解这些机制,结合实际场景灵活运用,才能构建高效、稳定的并发程序
相关文章:
多线程进阶核心知识详解(通俗版)
Java多线程进阶详解 一、锁策略:如何高效管理资源竞争 在多线程环境中,锁是协调资源访问的核心机制。不同的锁策略适用于不同的场景,理解它们的差异能帮助优化程序性能。 1. 乐观锁 vs 悲观锁 悲观锁: 核心思想:假设…...
大模型中的KV Cache
1. KV Cache的定义与核心原理 KV Cache(Key-Value Cache)是一种在Transformer架构的大模型推理阶段使用的优化技术,通过缓存自注意力机制中的键(Key)和值(Value)矩阵,避免重复计算&…...
FHQ平衡树
FHQ平衡树 大致是这样的题目: 您需要动态地维护一个可重集合 M M M,并且提供以下操作: 向 M M M 中插入一个数 x x x。从 M M M 中删除一个数 x x x(若有多个相同的数,应只删除一个)。查询 M M M 中…...
力扣算法---总结篇
5.13 数组总结 数组是存放在连续内存空间上的相同类型数据的集合。 数组可以方便的通过下标索引的方式获取到下标对应的数据。 正是因为数组在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。 数组的元素是不…...

ABAP+旧数据接管的会计年度未确定
导资产主数据时,报错旧数据接管的会计年度未确定 是因为程序里面使用了下列函数AISCO_CALCULATE_FIRST_DAY,输入公司代码,获取会计年度,这个数据是在后台表T093C表中取数的,通过SE16N可以看到后台表数据没有数…...
Java【10_1】用户注册登录(面向过程与面向对象)
测试题 1、基于文本界面实现登录注册的需求(要求可以满足多个用户的注册和登录) 通过工具去完成 公共类: public class User { private int id;//用户编号 private int username;//用户名 private int password;//密码 private String name;//真…...

养生:打造健康生活的全方位策略
在生活节奏不断加快的当下,养生已成为提升生活质量、维护身心平衡的重要方式。从饮食、运动到睡眠,再到心态调节,各个方面的养生之道共同构建起健康生活的坚实基础。以下为您详细介绍养生的关键要点,助您拥抱健康生活。 饮食养生…...

贪吃蛇游戏排行榜模块开发总结:从数据到视觉的实现
一、项目背景与成果概览 在完成贪吃蛇游戏核心玩法后,本次开发重点聚焦于排行榜系统的实现。该系统具备以下核心特性: 🌐 双数据源支持:本地存储(localStorage)与远程API自由切换 🕒 时间维度统计:日榜/周榜/月榜/全时段数据筛选 🎮 模式区分:闯关模式(关卡进度…...
pytorch 数据预处理和常用工具
文章目录 NumPyNumpy数据结构安装和使用NumPy Matplotlib的安装和导入安装和导入Matplotlib绘制基础图画折线图散点图柱状图图例 数据清洗据清洗的作用Pandas进行数据清洗Pandas数据结构Series 数据结构DataFrame数据结构 Pandas数据清洗常用代码 特征工程主成分分析线性判别分…...
如何界定合法收集数据?
首席数据官高鹏律师团队 在当今数字化时代,数据的价值日益凸显,而合法收集数据成为了企业、机构以及各类组织必须严守的关键准则。作为律师,深入理解并准确界定合法收集数据的范畴,对于保障各方权益、维护法律秩序至关重要。 一…...
企业对数据集成工具的需求及 ETL 工具工作原理详解
当下,数据已然成为企业运营发展过程中的关键生产要素,其重要性不言而喻。 海量的数据分散在企业的各类系统、平台以及不同的业务部门之中,企业要充分挖掘这些数据背后所蕴含的巨大价值,实现数据驱动的精准决策,数据集…...
内核深入学习3——分析ARM32和ARM64体系架构下的Linux内存区域示意图与页表的建立流程
内核深入学习3——ARM32/ARM64在Linux内核中的实现(2) 今天我们来讨论的是一个硬核的内容,也是一个老生常谈的话题——那就是分析ARM32和ARM64体系架构下的Linux内存区域示意图的内容。对于ARM64的部分,我们早就知道一个基本的…...
MapReduce基本介绍
核心思想 分而治之:将大规模的数据处理任务分解成多个可以并行处理的子任务,然后将这些子任务分配到不同的计算节点上进行处理,最后将各个子任务的处理结果合并起来,得到最终的结果。 工作流程 Map 阶段: 输入数据被…...

屏幕与触摸调试
本章配套视频介绍: 《28-屏幕与触摸设置》 【鲁班猫】28-屏幕与触摸设置_哔哩哔哩_bilibili LubanCat-RK3588系列板卡都支持mipi屏以及hdmi显示屏的显示。 19.1. 旋转触摸屏 参考文章 触摸校准 参考文章 旋转触摸方向 配置触摸旋转方向 1 2 # 1.查看触摸输入设备 xinput…...

使用 百度云大模型平台 做 【提示词优化】
1. 百度云大模型平台 百度智能云千帆大模型平台  平台功能:演示了阿里云大模型的百炼平台,该平台提供Prompt工程功能,支持在线创建和优化Prompt模板模板类型:平台提供多种预制模板,同时也支持用户自定义…...
C 语言_常见排序算法全解析
排序算法是计算机科学中的基础内容,本文将介绍 C 语言中几种常见的排序算法,包括实现代码、时间复杂度分析、适用场景和详细解析。 一、冒泡排序(Bubble Sort) 基本思想:重复遍历数组,比较相邻元素,将较大元素交换到右侧。 代码实现: void bubbleSort(int arr[], i…...

IJCAI 2025 | 高德首个原生3D生成基座大模型「G3PT」重塑3D生成的未来
国际人工智能联合会议(IJCAI)是人工智能领域最古老、最具权威性的学术会议之一,自1969年首次举办以来,至今已有近六十年的历史。它见证了人工智能从萌芽到蓬勃发展的全过程,是全球人工智能研究者、学者、工程师和行业专…...

Samtec助力电视广播行业
【摘要前言】 现代广播电视技术最有趣的方面之一就是界限的模糊。过去,音频和视频是通过射频电缆传输的模拟技术采集的,而现在,数字世界已经取代了模拟技术。物理胶片和磁带已让位于数字存储设备和流媒体。 在这个过程中,连接器…...

密码学--仿射密码
一、实验目的 1、通过实现简单的古典密码算法,理解密码学的相关概念 2、理解明文、密文、加密密钥、解密密钥、加密算法、解密算法、流密码与分组密码等。 二、实验内容 1、题目内容描述 ①随机生成加密密钥,并验证密钥的可行性 ②从plain文件读入待…...
生成式图像水印研究综述
生成式图像水印研究综述 一、引言二、生成式图像水印研究背景三、生成式图像水印算法研究进展3.1 基于流模型的方案3.2 基于生成对抗网络的方案3.3 基于扩散模型的方案3.3.1 修改图像数据3.3.2 调整生成模型3.3.3 修改隐变量空间四、算法的性能与评价指标五、常用数据集六、本章…...
TCP协议详细讲解及C++代码实例
目录 一. TCP协议详细讲解及C代码实例1、TCP协议概述2、TCP通信流程1) 三次握手2) 数据传输3) 四次挥手 3、关键点解析1) 套接字创建2) 三次握手实现3) 数据传输4) 四次挥手实现 4、TCP与UDP对比 一. TCP协议详细讲解及…...
深度剖析:Vue2 项目兼容第三方库模块格式的终极解决方案
当我们为 Vue2 项目引入某些现代 JavaScript 库时,常常会遇到这样的报错: error in ./node_modules/some-lib/lib/index.mjs Cant import the named export xxx from non EcmaScript module这类问题的本质是模块格式的世纪之争 —— ES Moduleÿ…...
APISQL免费版安装教程(视频)
APISQL 一款通用的API开发管理软件,支持将主流数据库中的表、视图、SQL语句、存储过程等快速封装为标准的 RESTful API,支持多种安全认证方式和可视化管理界面。适用于接口开发、系统集成、数据共享等场景。 支持主流数据库的表、视图、自定义函数、存储…...

SpringBoot整合MQTT实战:基于EMQX实现双向设备通信(附源码)
简言: 在万物互联的时代,MQTT协议凭借其轻量级、高效率的特性,已成为物联网通信的事实标准。本教程将带领您在Ubuntu系统上搭建EMQX 5.9.0消息服务器,并使用Spring Boot快速实现两个客户端的高效通信。通过本指南,您将…...

从零开始掌握FreeRTOS(2)链表之节点的定义
目录 节点 节点定义 节点实现 根节点 根节点定义 精简节点定义 根节点实现 在上篇文章,我们完成了 FreeRTOS 的移植。在创建任务之前,我们需要先了解FreeRTOS的运转机制。 FreeRTOS是一个多任务系统,由操作系统来管理执行每个任务。这些任务全都挂载到一个双向循…...
Java的While循环写的出票简单程序
import java.util.Scanner;public class Hello {public static void main(String[] args) {Scanner in new Scanner(System.in);int balance 0;while(true){System.out.print("请投币: ");int amount in.nextInt();balance balance amount;if(balance >10 )…...
详解Windows(十一)——网络连接设置
Windows网络连接设置完全指南 1. Windows网络连接基础 网络连接类型 有线连接: 通过网线将电脑连接到路由器或调制解调器优点:连接稳定,速度快,延迟低适合:需要高速稳定网络的场景,如游戏、大文件下载、…...
多线程爬虫语言选择与实现
之前文中有人提到:想要一个简单易用、能快速实现多线程爬虫的方案,而且目标是小网站,基本可以确定对反爬虫措施要求不高,这些就比较简单了。 以往我肯定要考虑常见的编程语言中哪些适合爬虫。Python、JavaScript(Node…...

【数据结构】——双向链表
一、链表的分类 我们前面学习了单链表,其是我们链表中的其中一种,我们前面的单链表其实全称是单向无头不循环链表,我们的链表从三个维度进行分类,一共分为八种。 1、单向和双向 可以看到第一个链表,其只能找到其后一个…...
AI助力:零基础开启编程之旅
一、代码调试 三步解决BUG 1. 错误信息翻译 指令模板: 错误诊断模式我遇到【编程语言】报错“粘贴报错信息“ 请: 用小白能懂的话解释问题本质标注可能引发该错误的三个场景给出最可能的修复方案和其他备选方案 2. 上下文分析 进阶指令 结合上下文代…...