并发安全内容

JUC包下并发安全使用的类

线程池

  • ThreadPoolExecutor
  • Executors

并发集合类

  • ConcurrentHashMap
  • CopyOnWriteArrayList

同步工具类

  • CountDownLatch
  • CyclicBarrier
  • Semaphore

原子类

  • AtomicInteger
  • AtomicReference

Java中常用的锁和使用场景

  • 内置锁(synchronized):Java中的synchronized关键字是内置锁机制的基础,可以用于方法或代码块。当一个线程进入synchronized代码块或方法时,它会获取关联对象的锁;当线程离开该代码块或方法时,锁会被释放。如果其他线程尝试获取同一个对象的锁,它们将被阻塞,直到锁被释放。其中,syncronized加锁时有无锁、偏向锁、轻量级锁和重量级锁几个级别。偏向锁用于当一个线程进入同步块时,如果没有任何其他线程竞争,就会使用偏向锁,以减少锁的开销。轻量级锁使用线程栈上的数据结构,避免了操作系统级别的锁。重量级锁则涉及操作系统级的互斥锁
  • ReentrantLock:java.util.concurrent.locks.ReentrantLock是一个显式的锁类,提供了比synchronized更高级的功能,如可中断的锁等待、定时锁等待、公平锁选项等。ReentrantLock使用lock()和unlock()方法来获取和释放锁。其中,公平锁按照线程请求锁的顺序来分配锁,保证了锁分配的公平性,但可能增加锁的等待时间。非公平锁不保证锁分配的顺序,可以减少锁的竞争,提高性能,但可能造成某些线程的饥饿
  • 读写锁(ReadWriteLock):java.util.concurrent.locks.ReadWriteLock接口定义了一种锁,允许多个读取者同时访问共享资源,但只允许一个写入者。读写锁通常用于读取远多于写入的情况,以提高并发性
  • 乐观锁和悲观锁:悲观锁(Pessimistic Locking)通常指在访问数据前就锁定资源,假设最坏的情况,即数据很可能被其他线程修改。synchronized和ReentrantLock都是悲观锁的例子。乐观锁(Optimistic Locking)通常不锁定资源,而是在更新数据时检查数据是否已被其他线程修改。乐观锁常使用版本号或时间戳来实现
  • 自旋锁:自旋锁是一种锁机制,线程在等待锁时会持续循环检查锁是否可用,而不是放弃CPU并阻塞。通常可以使用CAS来实现。这在锁等待时间很短的情况下可以提高性能,但过度自旋会浪费CPU资源

synchronized锁的升级

  • 为什么要升级:在 JDK1.5 及之前,synchronized 完全依赖操作系统内核的互斥量实现,是典型的重量级锁,每次加锁解锁都需要完成用户态到内核态的切换,性能开销极大
  • 锁升级的哲学逻辑
能不加锁就不加锁(无锁) 只有一个线程来?那就记住你(偏向锁) 偶尔有第二个线程来?你们自旋抢一下就行(轻量级锁) 很多人来抢?老实排队,让操作系统管(重量级锁)

Mark Word

  • Mark Word存在对象头中
  • 对象头是 JVM 存储对象元信息的地方,和你写的业务字段无关。主要包含 Mark Word(存锁信息、hashcode、GC年龄)和 类型指针(指向类的元数据)
┌──────────────────────────────────────────────────────┐ │ │ │ 一个 Java 对象在内存中的布局 │ │ │ ├──────────────────────────────────────────────────────┤ │ │ │ ┌────────────────────────────────────────────┐ │ │ │ 对象头 (Header) │ │ │ │ ┌─────────────────────┬────────────────┐ │ │ │ │ │ Mark Word │ Klass Pointer │ │ │ │ │ │ (64 bit) │ (32/64 bit) │ │ │ │ │ └─────────────────────┴────────────────┘ │ │ │ │ ┌────────────────────────────────────┐ │ │ │ │ │ Array Length (仅数组对象有) │ │ │ │ │ │ (32 bit) │ │ │ │ │ └────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────┐ │ │ │ 实例数据 (Instance Data) │ │ │ │ 对象的字段值(int age, String name ...) │ │ │ └────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────┐ │ │ │ 对齐填充 (Padding) │ │ │ │ 使对象总大小为 8 字节的整数倍 │ │ │ └────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────┘
  • Mark Word里面存的东西
  • 锁信息 当前是偏向锁/轻量级锁/重量级锁,以及谁持有锁
  • hashcode 调用 hashCode() 后存入,懒加载的
  • GC分代年龄 4 bit,所以最大值 15,这就是为什么最大分代年龄是 15
  • 类型指针相关 指向对象属于哪个类
┌─────────────┬──────────────────────────────────────┬────────┬─────────────┐ │ 状态 │ 内容 (64 bit) │ 标志位 │ 是否存锁信息│ ├─────────────┼──────────────────────────────────────┼────────┼─────────────┤ │ │ unused:25 │ │ │ │ 无锁 │ hashcode:31 │ 001 │ 否 │ │ │ age:4 │ │ │ │ │ biased_lock:0 │ │ │ ├─────────────┼──────────────────────────────────────┼────────┼─────────────┤ │ │ thread:54 │ │ │ │ 偏向锁 │ epoch:2 │ 101 │ 是(偏向) │ │ │ age:4 │ │ │ │ │ biased_lock:1 │ │ │ ├─────────────┼──────────────────────────────────────┼────────┼─────────────┤ │ │ ptr_to_lock_record:62 │ 00 │ 是(轻量) │ │ 轻量级锁 │ │ │ │ ├─────────────┼──────────────────────────────────────┼────────┼─────────────┤ │ │ ptr_to_heavyweight_monitor:62 │ 10 │ 是(重量) │ │ 重量级锁 │ │ │ │ ├─────────────┼──────────────────────────────────────┼────────┼─────────────┤ │ │ 空 │ 11 │ 否 │ │ GC标记 │ │ │ │ └─────────────┴──────────────────────────────────────┴────────┴─────────────┘

从低级到高级锁

无锁(0 01)
所有线程都可以自由访问,没有任何锁信息。 对象刚 new 出来就是这个状态。 hashcode、GC分代年龄都存在 Mark Word 里。
偏向锁(1 01)
Thread A 第一次进入 synchronized 块 │ ├─ 用 CAS 把自己的线程ID 写入 Mark Word │ └─ 写入成功 → 以后 Thread A 再来,直接比较线程ID 匹配就直接进入,0 开销(连CAS都不用) Thread A 再次进入: 只需要检查 Mark Word 中的 threadID == 自己的 ID? ├─ 是 → 直接进入(无任何同步操作,极致优化) └─ 否 → 说明有另一个线程来了,触发撤销 Thread B 也来申请这把锁 │ ├─ Thread B 检查发现 threadID ≠ 自己 │ └─ 触发偏向锁撤销: 1. 暂停拥有偏向锁的线程 Thread A(需要等安全点 safepoint) 2. 检查 Thread A 是否还活着 │ ├─ Thread A 已退出同步块 → 锁对象恢复为无锁状态 │ 然后 Thread B 重新尝试获取 │ └─ Thread A 还在同步块中 → 升级为轻量级锁
轻量级锁(0 0)
  • 一般锁都是synchronized(对象)
  • 线程要用这个锁的时候,会将这个对象的Mark Word复制到这个线程的Lock Record中,然后把对象的Mark Word指向线程的Lock Record中
  • 不用的时候写回去
  • 拿锁的过程
Thread A 要执行 synchronized(obj): 第1步:在 Thread A 的栈帧中创建一个 Lock Record ┌─────────────────┐ │ Lock Record │ │ [ 空 ] │ ← 还没填东西 └─────────────────┘ 第2步:把 obj 的 Mark Word 复制到 Lock Record 里 ┌─────────────────┐ obj 对象头 │ Lock Record │ ┌──────────────┐ │ [ hashcode, │ ←── │ Mark Word │ │ age, 001 ] │ 复制 │ hashcode, │ └─────────────────┘ │ age, 001 │ └──────────────┘ 第3步:CAS 修改 obj 的 Mark Word,让它指向 Lock Record obj 对象头 ┌──────────────────────┐ │ ptr → Lock Record │00│ ← Mark Word 变成了指针 + 00标志 └──────────────────────┘ CAS 的含义: 比较 obj 的 Mark Word 是否还是第2步复制时的那个值 ├─ 是 → 说明没人抢,成功,把 Mark Word 改成指针 └─ 不是 → 说明有人抢了,CAS 失败 第4步:CAS 成功 → Thread A 获得轻量级锁,进入同步块
  • 释放锁的过程
Thread A 退出 synchronized(obj): 第1步:把 Lock Record 里备份的 Displaced Mark Word 通过 CAS 写回 obj 的 Mark Word obj 对象头 ┌──────────────────────┐ ┌─────────────────┐ │ hashcode, age, 001 │ ←──CAS──│ Lock Record │ └──────────────────────┘ │ [ hashcode, │ │ age, 001 ] │ └─────────────────┘ 第2步:CAS 成功 → 释放完毕,对象恢复无锁状态 CAS 失败 → 说明锁已经膨胀成重量级锁了,需要唤醒等待的线程
  • 竞争过程
Thread A 正持有轻量级锁 Thread B 这时也想获取这把锁 第1步:Thread B 执行 CAS 尝试修改 Mark Word → 失败(已被 A 改了) 第2步:Thread B 不会立即放弃,而是进入 "自旋" 状态 自旋 = 一个 while 循环,反复尝试 CAS while (true) { if (CAS 成功) { 拿到锁,退出循环; break; } // 失败了就继续循环,再试 } 第3步:自旋结果有两种: ├─ 自旋过程中 Thread A 释放了锁 → Thread B CAS 成功,拿到锁 │ (皆大欢喜,全程用户态,没有系统调用) │ └─ 自旋次数超过阈值还没拿到 → 膨胀为重量级锁(下面讲)
重量级锁(0 1)
  • Monitor
每个 Java 对象都可以关联一个 Monitor 对象(重量级锁激活时才创建) ┌─────────────────────────────────────────┐ │ ObjectMonitor │ │ │ │ _owner ──────→ 当前持有锁的线程 │ │ (只有一个) │ │ │ │ _EntryList ──→ 排队等锁的线程队列 │ │ (都睡着,等被唤醒) │ │ │ │ _WaitSet ────→ 调用了 wait() 的线程 │ │ (主动等待的线程) │ │ │ │ _count ──────→ 重入计数 │ │ (同一线程进入几次) │ └─────────────────────────────────────────┘
  • 加锁过程
Thread C 想获取 obj 的锁: 第1步:JVM 检查 obj 的 Mark Word,发现是重量级锁(标志位 10) Mark Word → 指向一个 ObjectMonitor 第2步:检查 Monitor 的 _owner ├─ null → CAS 设置自己为 _owner,拿到锁 ✓ ├─ 就是自己 → 重入,_count++,拿到锁 ✓ └─ 其他线程 → Thread C 进入阻塞流程 ↓ 第3步:阻塞流程(开销大就在这里) ① Thread C 被放入 _EntryList 队列 ② Thread C 调用操作系统的 mutex_lock() 系统调用 ③ OS 把 Thread C 挂起(从运行态 → 阻塞态) ④ 这涉及 用户态 ↔ 内核态 切换,成本极高 ⑤ Thread C 就睡着了,不消耗 CPU,但上下文切换代价大
  • 释放锁过程
Thread A 退出 synchronized: 第1步:设置 _owner = null 第2步:从 _EntryList 中唤醒一个等待的线程 第3步:被唤醒的线程重新竞争锁 (不是直接给它,而是让它和其他线程公平竞争)

相关新闻

ESP8285电机控制器MQTT上云实战:硬件选型、固件架构与MQTTX联调

ESP8285电机控制器MQTT上云实战:硬件选型、固件架构与MQTTX联调

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 2:03:39 阅读更多 →
从下载到第一张卫星图,SatDump实操全流程

从下载到第一张卫星图,SatDump实操全流程

从下载到第一张卫星图,SatDump实操全流程 【免费下载链接】SatDump A generic satellite data processing software. 项目地址: https://gitcode.com/GitHub_Trending/sa/SatDump 手上有 RTL-SDR,频谱上却只看得见瀑布图的色块?缺的就…

2026/10/21 2:03:39 阅读更多 →
Terminal-Bench完整指南:4步跑通你的第一个AI终端评测

Terminal-Bench完整指南:4步跑通你的第一个AI终端评测

Terminal-Bench完整指南:4步跑通你的第一个AI终端评测 【免费下载链接】terminal-bench-1 A benchmark for LLMs on complicated tasks in the terminal 项目地址: https://gitcode.com/GitHub_Trending/tb/terminal-bench-1 你的Agent演示很精彩&#xff0c…

2026/10/21 2:02:39 阅读更多 →

最新新闻

Quartz动态设置并发数量

Quartz动态设置并发数量

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 2:48:00 阅读更多 →
AI Agent ROI评估指南:从成本结构到收益测算全解析

AI Agent ROI评估指南:从成本结构到收益测算全解析

1. 先别急着算账,想清楚AI Agent的ROI和传统IT项目有什么不同这两年不少公司都开始折腾AI Agent,有的把它接到客服系统,有的让它帮着写代码,还有的用它处理合同和报表。但当你真坐下来算这笔账时,会发现一个尴尬的问题…

2026/10/21 2:48:00 阅读更多 →
基于卷积神经网络的食物图像识别实战:从ResNet迁移学习到部署

基于卷积神经网络的食物图像识别实战:从ResNet迁移学习到部署

简介:基于卷积神经网络的食物图像识别项目完整代码与数据包,面向具备Python基础并希望实践CNN图像分类的开发者与学习者。资源围绕TensorFlow与tf.keras构建食物识别模型,涵盖数据预处理、网络定义、训练评估与预测全流程,并引入迁…

2026/10/21 2:48:00 阅读更多 →
SECS-II/HSMS调试工具实战:从协议原理到模拟器应用

SECS-II/HSMS调试工具实战:从协议原理到模拟器应用

简介:面向半导体制造与MES系统集成场景,这份SECS-II HSMS调试工具模拟器适合设备工程师、上位机开发人员使用。它可模拟客户端与服务端,用于验证自定义程序是否符合SECS-II通信标准,减少现场联调时的错误与返工。压缩包为rar格式&…

2026/10/21 2:48:00 阅读更多 →
eNSP校园网拓扑设计实战:VLAN划分、DHCP配置与静态路由全解析

eNSP校园网拓扑设计实战:VLAN划分、DHCP配置与静态路由全解析

简介:面向计算机网络期末设计、课程设计及eNSP仿真练习的完整项目资料包,围绕某中学校园网络拓扑设计展开。方案包含网络拓扑选型、综合布线系统规划、教学楼/行政楼/宿舍接入设计,以及VLAN划分、IP地址分配、路由协议配置等模拟配置要点&…

2026/10/21 2:48:00 阅读更多 →
思科模拟器6.2:从安装到避坑的完整实战指南

思科模拟器6.2:从安装到避坑的完整实战指南

简介:这是一份思科模拟器6.2安装包,官方名称为Packet Tracer,面向网络技术学习者、思科认证考生以及开展网络实验教学的教师。软件以图形化方式搭建虚拟网络环境,可模拟路由器、交换机、无线接入点、防火墙等设备,支持…

2026/10/21 2:47:00 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →