Java锁机制知识点

一、锁的基础概念

1.1 什么是锁

在并发编程中,锁是用于控制多个线程对共享资源进行访问的机制。锁可以保证在同一时刻最多只有一个线程访问共享资源,从而保证数据的一致性。

1.2 锁的分类
  • 可重入锁 vs 不可重入锁:可重入锁允许同一个线程多次获得同一把锁,如synchronizedReentrantLock;不可重入锁要求线程在释放锁后才能再次获得锁。
  • 公平锁 vs 非公平锁:公平锁保证线程按照申请锁的顺序依次获得锁,类似于“先来先得”,如ReentrantLock在构造时指定true可实现公平锁;非公平锁不保证线程获取锁的顺序,可能会出现线程插队现象,ReentrantLock默认实现为非公平锁。
  • 独占锁 vs 共享锁:独占锁保证在同一时刻,只有一个线程可以获得锁,如写锁;共享锁允许多个线程同时获得锁,如读写锁中的读锁。
  • 乐观锁 vs 悲观锁:悲观锁假设线程间会发生资源争用,在访问共享资源前先加锁,如synchronizedReentrantLock;乐观锁假设线程间不会发生冲突,不加锁,访问数据时判断是否发生了冲突,若冲突则重试,如CAS(Compare-And-Swap)。
  • 偏向锁、轻量级锁、重量级锁:这三种锁特指synchronized锁的状态,它们通过JVM内部的对象头(Mark Word)来控制锁的状态。偏向锁适用于线程没有竞争的场景;轻量级锁通过CAS操作来避免线程阻塞,适合多线程之间竞争较少的场景;重量级锁通过操作系统的同步机制来实现,线程获取不到锁时会被阻塞,适合竞争激烈且锁持有时间较长的场景。锁的升级路径为:无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁。

二、常见锁机制详解

2.1 synchronized关键字
  • 基本使用
//修饰实例方法
public class SynchronizedExample {public synchronized void instanceMethod() {// 方法体}
}
//修饰静态方法
public class SynchronizedExample {public static synchronized void staticMethod() {// 方法体}
}
//修饰代码块
public class SynchronizedExample {public void blockMethod() {synchronized (this) {// 同步代码块}}
}
  • 实现原理synchronized的实现原理主要包括对象头中的Mark Word、monitor entermonitor exit,以及锁的升级过程(无锁 → 偏向锁 → 轻量级锁 → 重量级锁)。
  • 特性与缺点
    • 隐式锁:由JVM自动管理锁的获取与释放,程序员不需要手动操作。
    • 阻塞性:线程在获取不到锁时会被阻塞,直到锁被释放。
    • 不可中断:线程一旦获得锁就会一直持有,直到执行完同步代码块或方法才会释放锁。
    • 性能问题:由于是阻塞锁,在高并发环境下可能会引起较大的性能损失,尤其是在锁竞争激烈时。
  • 适用场景:适用于简单的同步场景,当需要同步的代码块较小,且竞争不激烈时;也适合锁粒度较粗的同步需求。
2.2 ReentrantLock
  • 基本使用
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockExample {private final ReentrantLock lock = new ReentrantLock();private int count = 0;public void increment() {lock.lock(); // 获取锁try {count++;} finally {lock.unlock(); // 释放锁}}// 支持超时的获取锁方式public boolean tryIncrement() {if (lock.tryLock()) { // 尝试获取锁try {count++;return true;} finally {lock.unlock();}}return false;}
}
  • 高级特性
    • 可中断锁lock.lockInterruptibly()方法允许线程在等待获取锁时响应中断。
    • 公平锁:可以创建公平锁,确保按照请求锁的顺序进行,等待时间最长的线程先获得锁。
    • 条件变量:提供Condition接口,用于线程间的协调。
  • 特性与优缺点
    • 优点:支持可中断的锁等待、锁超时、非阻塞获取锁;可以创建公平锁;提供了更多的控制选项。
    • 缺点:需要手动获取和释放锁,代码容易出错。
  • 适用场景:需要可中断锁的场景;需要公平锁的场景;需要尝试锁的场景。
2.3 ReadWriteLock
  • 概述ReadWriteLock提供了读写分离的锁机制,允许多个线程同时读取资源,但在写入时只能有一个线程获取写锁。其实现类通常是ReentrantReadWriteLock
  • 工作原理
    • 读锁:多个读线程可以同时获取,读锁不会阻塞其他读线程。
    • 写锁:写锁是独占的,写锁获取时会阻塞所有读线程和写线程。
  • 特性与优缺点
    • 优点:在读多写少的场景下,能够极大地提高并发性能。
    • 缺点:如果写操作较为频繁,性能提升不明显;可能会出现写饥饿问题。
  • 适用场景:适用于读多写少的场景,如缓存实现。
2.4 StampedLock
  • 核心特性
    • 乐观读:通过tryOptimisticRead()实现无锁读取,校验数据版本(邮戳)。若校验失败(期间有写操作),再升级为悲观读锁。
    • 三种模式:写锁、悲观读锁、乐观读。
  • 代码示例
import java.util.concurrent.locks.StampedLock;public class StampedLockExample {private final StampedLock stampedLock = new StampedLock();// 乐观读public void optimisticRead() {long stamp = stampedLock.tryOptimisticRead();// 读取数据if (!stampedLock.validate(stamp)) {stamp = stampedLock.readLock();try {// 重新读取数据} finally {stampedLock.unlockRead(stamp);}}}// 写操作public void write() {long writeStamp = stampedLock.writeLock();try {// 修改数据} finally {stampedLock.unlockWrite(writeStamp);}}
}
  • 缺点:不可重入,同一线程重复获取锁会导致死锁;API复杂,需手动处理锁升级和邮戳验证。
  • 适用场景:需要极高读并发且写冲突少的场景,如实时数据分析。

三、锁的优化技术

3.1 锁粗化

将多个紧邻的小范围加锁操作合并为一次较大的加锁操作,从而减少锁的频繁获取和释放,降低锁的开销。例如:

// 优化前
for (int i = 0; i < 100; i++) {synchronized (lock) {// 执行一些操作}
}// 优化后
synchronized (lock) {for (int i = 0; i < 100; i++) {// 执行一些操作}
}
3.2 锁消除

JVM在JIT编译时,通过逃逸分析判断加锁的对象是否只在当前线程内使用,如果确定不会发生线程竞争,JVM会自动将这些锁消除,从而避免不必要的锁操作。例如:

public String concatenate(String s1, String s2) {StringBuffer sb = new StringBuffer();sb.append(s1);sb.append(s2);return sb.toString();
}

在上述代码中,StringBuffer对象只在方法内部使用,不会被其他线程访问,因此JVM可以消除锁操作。

3.3 偏向锁

偏向于第一个获取它的线程,如果该线程再次进入同步块,锁不会进行竞争,直接获取锁。这种优化适用于锁竞争较少的场景,可以减少加锁的开销。

3.4 轻量级锁

核心思想是避免线程阻塞,它通过CAS操作来获取锁,从而避免了线程的上下文切换。如果线程竞争激烈,轻量级锁会升级为重量级锁。

3.5 自旋锁与自适应自旋

自旋锁是指当线程尝试获取锁而失败时,不会立即进入阻塞状态,而是进行短暂的忙等待(自旋),等待锁的释放后再尝试获取。Java中使用了自适应自旋技术,会根据前一次自旋的结果动态调整自旋次数。

四、死锁问题

4.1 死锁产生的条件
  • 互斥使用:资源一次只能被一个线程独占使用。
  • 不可抢占:资源请求者不能强制从资源占有者手中抢夺资源,资源只能由占有者主动释放。
  • 请求和保持:当资源请求者在请求其他资源的同时保持对原因资源的占有。
  • 循环等待:多个线程存在环路的锁依赖关系而永远等待下去。
4.2 死锁的预防方法
  • 破坏“循环等待”条件 - 锁顺序化:强制所有线程以全局一致的固定顺序获取锁。
  • 避免持有并等待:线程在获取所有需要的资源之前,不占用任何资源。
  • 允许抢占:允许线程在必要时抢占其他线程的资源。

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

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

相关文章

2025下半年软考软件设计师(中级)怎么高效备考,目标是稳过线!

25下半年软考开始进入备考阶段&#xff0c;现在咱们就抛开那些文绉绉的官话&#xff0c;用大白话来聊聊2025下半年软考软件设计师&#xff08;中级&#xff09;怎么高效备考&#xff0c;目标是稳过线&#xff01; 核心思想&#xff1a;抓大放小&#xff0c;真题为王&#xff0…

Jupyter常见操作(持续更新)

Jupyter常见操作&#xff08;持续更新&#xff09; 本文主要整理一些常见的或者比较简单的Jupyter操作&#xff0c;尽量保证一次性整理出来&#xff0c;方便需要但是忘记的情况下可以直接查&#xff0c;希望能当字典。 1.查看Jupyter内核 jupyter kernelspec list 2.使用指定…

连点成画面积计算算法

连点成画面积计算算法 问题分析与算法设计 1. 问题特征分析 闭合多边形(起点和终点相同)线段可能交叉形成复杂形状需要处理自交多边形可能有多个内部空洞点数较多(≥50个点),需要高效算法2. 解决方案选择 采用平面扫描算法结合多边形布尔运算来准确计算最外层边界包围的…

华为云Flexus+DeepSeek征文 | 华为云MaaS平台上的智能客服Agent开发:多渠道融合应用案例

华为云FlexusDeepSeek征文 | 华为云MaaS平台上的智能客服Agent开发&#xff1a;多渠道融合应用案例 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 总有一行代码&#xff0c;能点亮万千星辰。 &#x1f50d; 在技术的宇宙中&#xff0c;我愿做永不…

03.BUG

Bug 1.软件测试的生命周期2. BUG2.1 表述BUG的要素2.2 BUG级别2.3 BUG的声命周期 1.软件测试的生命周期 ​ 软件测试贯穿于软件的整个生命周期&#xff1a;软件测试的生命周期&#xff08;Software Testing Life Cycle, STLC&#xff09;,是指测试流程&#xff0c;这个流程是按…

【数据标注师】问答标注

目录 一、 **问答标注的认知底层架构**1. **三维评估体系**2. **四类问题处理范式** 二、 **五阶能力培养体系**▶ **阶段1&#xff1a;问题解析能力筑基&#xff08;2周&#xff09;**▶ **阶段2&#xff1a;答案质量评估训练**▶ **阶段3&#xff1a;复杂场景处理**▶ **阶段…

使用DBeaver 连接mysql,使用存储过程插入5万条数据

使用DBeaver连接MySQL并创建存储过程生成5万条数据 连接MySQL数据库 打开DBeaver&#xff0c;点击"数据库"菜单选择"新建连接"&#xff0c;选择MySQL驱动。填写主机、端口、数据库名称、用户名和密码等信息&#xff0c;测试连接成功后保存。 创建测试表…

某省赛题-windows内存取证

1.获取admin用户密码是多少&#xff1f; 这里我们使用hashdump之后用john爆破没有结果&#xff0c;然后使用lsadump出来了flag 2.获取ip和主机名是什么&#xff1f; 主机名&#xff1a; 看注册表 SAM&#xff1a;记录了所有的用户 SYSTEM&#xff1a;可以看主机名 SOFTWARE&a…

【软考高项论文】论信息系统项目的成本管理

摘要 在信息系统项目管理里&#xff0c;成本管理是极为关键的环节&#xff0c;直接影响项目的顺利开展与最终成败。本文结合项目管理实际情况&#xff0c;从项目成本基准的形成过程、项目S曲线的绘制以及成本控制的具体实施三个方面&#xff0c;详细阐述了对信息系统项目成本管…

AI人工智能技术应用于人社服务领域的创新研究报告

AI 人工智能技术应用于人社服务领域的创新研究报告 一、研究背景与市场概况 1.1 研究背景与政策环境 人工智能技术正深刻改变政府治理模式和公共服务方式。在国家全面推进数字化转型的战略背景下,人社部《数字人社建设行动实施方案》明确提出:到 2025 年,人社数字化底座…

javaEE-mybatis操作数据库

前言 在MySQL的学习阶段&#xff0c;我们知道了如何使用JDBC去操作&#xff0c;也正是因为学习了JDBC也知道其操作的繁琐&#xff0c;每次的CRUD操作都需要从数据库连接池中去获取数据库连接&#xff0c;然后再编写SQL语句&#xff0c;并绑定对应的参数&#xff0c;接着通过连…

移动端测试——如何解决iOS端无法打开弹窗式网页(Webkit)

目录 一、什么是webkit&#xff1f; 1. 核心定义 2. iOS 的特殊限制 3. 弹窗拦截的逻辑 二、为什么 iOS 必须用 WebKit&#xff1f; 1. 苹果的官方理由 2. 实际后果 3.然而…… 三、如何解决iOS端无法打开弹窗式网页&#xff1f; 1.用户 1.1 safari浏览器 1.2 夸克…

【github】从本地更新仓库里的文件笔记

1. 打开GitHub官网&#xff0c;并登录到您的账户。 2. 在页面右上角的搜索栏中&#xff0c;输入您要更新的仓库名称&#xff0c;并选择相应的仓库进入。 3. 在仓库页面中&#xff0c;找到并点击红色的“Code”按钮&#xff0c;然后复制仓库的HTTPS或者SSH链接。 4. 右键包含…

Excel基础:数据编辑

Excel是Windows下最常用的数据处理工具&#xff0c;本文详细介绍Excel的数据编辑功能&#xff0c;熟练掌握编辑技巧能可以极大提升工作效率&#xff0c;文章最后附加了一张总结思维导图&#xff0c;方便大家查找和记忆。 文章目录 一、数据输入1.1 覆盖输入1.2 追加输入1.3 任…

JavaScript中Object()的解析与应用

在JavaScript中&#xff0c;Object() 是一个基础构造函数&#xff0c;用于创建对象或转换值为对象类型。它既是语言的核心组成部分&#xff0c;也提供了一系列静态方法用于对象操作。以下是详细解析和应用示例&#xff1a; 一、Object() 的基本行为 作为构造函数&#xff08;…

stream使用案例

1.1 查找所有的偶数并求和 public static void p1() { List<Integer> numbers Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); int sum numbers.stream() .filter(num -> num % 2 0) .mapToInt(Integer::intValue) .sum() ; System.err.printf…

力扣 刷题(第七十一天)

灵感来源 - 保持更新&#xff0c;努力学习 - python脚本学习 4的幂 解题思路 位运算条件&#xff1a;4 的幂的二进制表示中只有一个 1&#xff0c;且位于奇数位&#xff08;如 4 100&#xff0c;4 10000&#xff09;。模运算条件&#xff1a;4 的幂减 1 后能被 3 整除&…

深度学习使用Pytorch训练模型步骤

训练模型是机器学习和深度学习中的核心过程&#xff0c;旨在通过大量数据学习模型参数&#xff0c;以便模型能够对新的、未见过的数据做出准确的预测。 训练模型通常包括以下几个步骤&#xff1a; 1.数据准备&#xff1a; 收集和处理数据&#xff0c;包括清洗、标准化和归一化…

Unity_导航操作(鼠标控制人物移动)_运动动画

文章目录 前言一、Navigation 智能导航地图烘焙1.创建Plan和NavMesh Surface2.智能导航地图烘焙 二、MouseManager 鼠标控制人物移动1.给场景添加人物&#xff0c;并给人物添加导航组件2.编写脚本管理鼠标控制3.给人物编写脚本&#xff0c;订阅事件&#xff08;添加方法给Mouse…

6. 接口分布式测试pytest-xdist

pytest-xdist实战指南&#xff1a;解锁分布式测试的高效之道 随着测试规模扩大&#xff0c;执行时间成为瓶颈。本文将带你深入掌握pytest-xdist插件&#xff0c;利用分布式测试将执行速度提升300%。 一、核心命令解析 加速安装&#xff08;国内镜像&#xff09; pip install …