【多线程初阶】synchronized锁

article/2025/8/14 22:52:54

文章目录

  • 🌅synchronized关键字
    • 🌊 synchronized 的互斥
    • 🌊 synchronized 的变种写法
      • 🏄‍♂️synchronized 修饰代码块 :明确指定锁哪个对象
      • 🏄‍♂️synchronized 修饰方法
    • 🌊 synchronized 的可重入性
      • 🏄‍♂️可重入锁实现原理
      • 🏄‍♂️JVM怎么区分{ } 是synchronized的{}

🌅synchronized关键字

monitor lock 是JVM中采用的一个术语,使用锁的过程中抛出一些异常,可能会看到,监视器锁这样的报错信息

🌊 synchronized 的互斥

synchronized 会起到互斥的效果,某个线程执行到某个对象的 synchronized 中时,其他线程如果也执行到同一个对象 synchronized就会阻塞等待

  • 进入 synchronized 修饰的代码块,相当于 加锁
  • 退出 synchronized 修饰的代码块,相当于 解锁
synchronized {	//进入代码块,加锁//执行一些要保护的逻辑
}				//退出代码块,解锁

synchronized 用的锁是存在Java对象里的
可以粗略理解成,每个对象在内存在存储的时候,都存有一块内存表示当前的"锁定状态(类似于卫生间的"有人/无人")
如果当前是"无人"状态,那么就可以使用,使用时需要设为"有人"状态
如果当前是"有人"状态,呢么其他人无法使用,只能排队

理解阻塞等待:
针对每一把锁,操作系统内部都维护了一个等待队列,当这个锁被某个线程占有的时候,其他线程尝试进行加锁,就加不上了,就会阻塞等待,一直等到之间的线程解锁之后,由操作系统唤醒一个新的线程,再来获取到这个锁
注意:

  • 上一个线程解锁之后,下一个线程并不是立即就能获取到锁,而是要靠操作系统来"唤醒",这也是操作系统线程调度的一部分工作
  • 假设由 A B C 三个线程,线程 A 先获取到锁,然后 B 尝试获取锁,然后 C再尝试获取锁,此时 B 和 C都在阻塞队列中排队等待,但是当 A 释放锁之后,虽然 B 比 C先来,但是B 不一定就能获取锁,而是和 C 重新竞争,并不遵守先来后到的规则

在这里插入图片描述
两个线程,针对同一个对象加锁,才会产生互斥效果(一个线程加上锁了,另一个线程就得阻塞等待,等到第一个线程释放锁,才有机会)

如果是不同的锁对象,此时不会有互斥效果,线程安全没问题,没有得到改变

在这里插入图片描述

public class Demo17 {private static int count = 0;public static void main(String[] args) {Object locker = new Object();Thread t1 = new Thread(() ->{for (int i = 0; i < 500000; i++) {synchronized (locker){count++;}}System.out.println(" t1 结束");});Thread t2 = new Thread(() ->{for (int i = 0; i < 500000; i++) {synchronized (locker){count++;}}System.out.println(" t2 结束");});}
}

分析一下上述代码的具体执行
在这里插入图片描述
Java中为啥使用 synchronized + 代码块的做法?而不是采用lock + unlock函数的方式来搭配呢?(其实在Java中也有 lock/unlock风格的锁,只不过一般很少使用)

Java采取 synchronized,就能确保,只要出了 } 一定能释放锁,无论因为 return 还是异常,无论里面调用了哪些其它代码,都可以确保unlock 操作执行到的

此时,其他语言也参考了Java这里的设定,C++提供了lock_guard机制,Python提供了with语句(上下文管理器),Go提供了defer关键字

本质上都是和synchronized一样的,都是出了代码块就能自动释放锁

🌊 synchronized 的变种写法

🏄‍♂️synchronized 修饰代码块 :明确指定锁哪个对象

  • 1.锁任意对象
public static void main(String[] args) {Object locker = new Object();Thread t1 = new Thread(() ->{synchronized (locker){count++;}});
  • 2.锁当前对象
public static void main(String[] args) {Thread t1 = new Thread(() ->{synchronized (this){}});

🏄‍♂️synchronized 修饰方法

  • 1.直接修饰普通方法 : 锁的SynchronziedDemo对象
  • 2.修饰静态方法 : 锁的SynchronziedDemo 类的对象
class Counter{private int count = 0;synchronized public void add(){count++;}public int get(){return count;}public synchronized  static void func(){synchronized (Counter.class){}}}
public class Demo18 {public static void main(String[] args) throws InterruptedException {Object locker = new Object();Counter counter = new Counter();Thread t1 = new Thread(() ->{for (int i = 0; i < 50000; i++) {counter.add();}});Thread t2 = new Thread(() ->{for (int i = 0; i < 50000; i++) {counter.add();}});t1.start();t2.start();t1.join();t2.join();System.out.println("count="+counter.get());}
}

针对上述代码,其中:
在这里插入图片描述

🌊 synchronized 的可重入性

synchronized 同步对同一条线程来说是可重入的,不会出现自己把自己锁死的问题

理解"把自己锁死"
一个线程没有释放锁,然后又尝试再次加锁
// 第一次加锁,加锁成功
lock();
// 第二次加锁,锁已经被占用,阻塞等待
lock();
按照之前对于锁的设定,第二次加锁的时候,就会阻塞等待,直到第一次的锁被释放,才能获取到第二个锁,但是释放第一个锁也是由该线程来完成的,结果这个线程不干了,无法进行解锁操作,这时候就会死锁

Java中的 synchronized 是可重入锁,因此没有上面的问题

在这里插入图片描述
比如以下代码的使用:

class Counter2{private int count = 0;public void add(){synchronized (this) {count++;}}public int get(){return count;}}
public class Demo19 {public static void main(String[] args) throws InterruptedException {Counter2 counter2 = new Counter2();Thread t1 = new Thread(() ->{for (int i = 0; i < 50000; i++) {synchronized (counter2){counter2.add();}}});t1.start();t1.join();System.out.println("count = "+counter2.get());}
}

在这里插入图片描述
死锁是一个非常严重的bug,使代码执行到这一块之后,就卡住
为了解决上述问题,Java的 synchronized 就引入了可重入的概念

在这里插入图片描述
在这里插入图片描述

🏄‍♂️可重入锁实现原理

可重入锁的实现原理,关键在于让锁对象,内部保存,当前是哪个线程持有这把锁,后续有线程针对这个锁加锁的时候,对比一下,锁持有者的线程是否和当前加锁的线程是同一个

在这里插入图片描述

🏄‍♂️JVM怎么区分{ } 是synchronized的{}

{ }这个大括号,只是Java代码角度理解的,JVM看到的是字节码
java => .class 这个过程编译器已经处理了
JVM 执行 .class

Java代码中看到的是{ },字节码中,对应的是不同的指令 { 涉及到加锁指令 } 涉及到解锁指令 像是 if else while 他们的 { } 是不会被编译成,加锁解锁指令的~~


http://www.hkcw.cn/article/QHwjmnAGaA.shtml

相关文章

使用 Cython 编译将.py文件加密成.so文件

文章目录 1. .so文件的核心意义和优势2. 使用 Cython 编译&#xff0c;将.py文件加密成.so文件 最近在学习在服务器上如何部署Python模型&#xff0c;不学不知道&#xff0c;一学吓一跳&#xff0c;要学好多啊&#xff0c;最近看到什么就记录一下什么吧。 1. .so文件的核心意义…

环赛里木湖公路自行车赛开赛 速度与激情点燃丝路热土

5月31日上午10时,中国新疆第十七届环赛里木湖(国际)公路自行车赛在精河县鸣枪开赛。首段比赛全长83.1公里,以速度与激情点燃了“中国枸杞之乡”精河县的丝路热土。骑手们从精河县出发,沿精阿高速疾驰,穿越艾比湖湿地和甘家湖梭梭林国家级自然保护区。开赛后仅10分钟,在顺…

南京大学通报施工方偷窃物品 施工单位被罚2000元

5月29日,南京大学基本建设处发布了一份关于对南京诚善科技有限公司执行合同违约金的通报。通报指出,南京大学三校区公共区域饮水机采购及安装项目的施工单位南京诚善科技有限公司的一名员工于5月13日在学校宿舍楼内偷窃学生物品。根据施工合同相关规定并经处办公会研究确认,…

java 反射 枚举与lambda表达式

目录 一.反射 1.概念&#xff1a;在运⾏时检查、访问和修改类、接⼝、字段和⽅法的机制 2.Class类 3.反射相关的类型 4.各类型对应的方法 ​编辑 5.代码示例 (1).class类方法 (2).Field类方法 (3).Constructor类方法 (4).Method类方法 6.总结 二.枚举 1.概念&#x…

【AI大模型】Ollama部署本地大模型DeepSeek-R1,交互界面Open-WebUI,RagFlow构建私有知识库

文章目录 DeepSeek介绍公司背景核心技术产品与服务应用场景优势与特点访问与体验各个DeepSeek-R系列模型的硬件需求和适用场景 Ollama主要特点优势应用场景安装和使用配置环境变量总结 安装open-webui下载和安装docker desktop配置镜像源安装open-webui运行和使用 RagFlow介绍主…

DeepSeek:全栈开发者视角下的AI革命者

无论是想要学习人工智能当做主业营收&#xff0c;还是像我一样作为开发工程师但依然要了解这个颠覆开发的时代宠儿&#xff0c;都有必要了解、学习一下人工智能。 近期发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;入行门槛低&#x…

什么是贝叶斯优化(Bayesian Optimization)?

贝叶斯最优化&#xff08;Bayesian Optimization&#xff09;是一种用于函数全局最优化的策略&#xff0c;特别适用于那些计算代价昂贵的黑箱函数&#xff08;如机器学习模型的超参数调优&#xff09;。其核心思想是通过构建一个代理模型&#xff08;通常是高斯过程或随机森林&…

Spring AI+DeepSeek快速构建AI智能机器人

引言 在AI技术蓬勃发展的当下&#xff0c;Spring生态推出了Spring AI项目&#xff0c;为Java开发者提供了便捷的AI集成方案。本文将演示如何用Spring AIDeepSeek V3 快速搭建一个具备自然语言处理能力的智能对话机器人。 一、环境准备 JDK 17 Maven/Gradle构建工具 DeepSe…

【大模型科普】大模型:人工智能的前沿(一文读懂大模型)

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈人工智能与大模型应用 ⌋ ⌋ ⌋ 人工智能&#xff08;AI&#xff09;通过算法模拟人类智能&#xff0c;利用机器学习、深度学习等技术驱动医疗、金融等领域的智能化。大模型是千亿参数的深度神经网络&#xff08;如ChatGPT&…

借用AI工具(cursor/vscode) 调试matlab代码(2025.4最新实测)

本文实测环境&#xff1a;MATLAB 2025a Windows 11 本文亮点&#xff1a;无需重写Python&#xff01;用AI直接优化现有MATLAB工程 一、AI调试MATLAB的紧迫性 因为matlab无法内置ai 工具 &#xff0c;别人都有的不能out了 另外说一声matlba2025a已经很改版很多了&#xff0c;与…

5 分钟用满血 DeepSeek R1 搭建个人 AI 知识库(含本地部署)

最近很多朋友都在问:怎么本地部署 DeepSeek 搭建个人知识库。 老实说,如果你不是为了研究技术,或者确实需要保护涉密数据,我真不建议去折腾本地部署。 为什么呢? 目前 Ollama 从 1.5B 到 70B 都只是把 R1 的推理能力提炼到 Qwen 和 Llama 的蒸馏版本上。 虽说性能是提升…

灰狼优化算法(GWO)(含ai创作)

GWO简介 灰狼优化算法&#xff08;Grey Wolf Optimizer&#xff0c;GWO&#xff09;是一种模仿灰狼狩猎行为的群体智能优化算法&#xff0c;由Seyedali Mirjalili等人在2014年提出。这种算法主要模拟了灰狼的社会等级结构和狩猎策略&#xff0c;用于解决各种优化问题。 在灰狼…

5步掌握MCP HTTP模式部署:从零开始搭建你的AI“邮局”!

&#x1f525;关注墨瑾轩&#xff0c;带你探索编程的奥秘&#xff01;&#x1f680; &#x1f525;超萌技术攻略&#xff0c;轻松晋级编程高手&#x1f680; &#x1f525;技术宝库已备好&#xff0c;就等你来挖掘&#x1f680; &#x1f525;订阅墨瑾轩&#xff0c;智趣学习不…

基于DeepSeek-Coder,实现Microi吾码低代码平台AI代码辅助生成的思路设想【辅助代码生成】

文章目录 引言一、整体架构设计二、实现流程与关键技术1. 构建领域数据集2. 模型训练与微调3. 生成代码的安全控制4. 平台集成与交互设计 三、效果优化与评估1. 效果展示2. 评估指标 四、未来优化方向结语 引言 低代码开发平台&#xff08;Microi吾码&#xff09;通过可视化交…

【DeepSeek+即梦AI:零基础生成专业级AI图片全流程指南(2025实战版)】

第一部分:工具认知篇——认识你的数字画笔 1.1 工具定位与核心价值 (讲师开场白)各位同学好,今天我们要解锁的是AI创作领域最具生产力的组合工具——DeepSeek+即梦AI。就像画家需要画笔与颜料,这对组合就是你的数字创作套装: • DeepSeek:国内顶尖的智能提示词工程师 …

【Ai学习】利用扣子(Coze)简单搭建图像生成工作流(小白初学版)

开始之前我们先了解一下我们准备使用的工具。 什么是扣子&#xff08;Coze&#xff09;&#xff1f; 官网链接&#xff1a;扣子 扣子&#xff08;Coze&#xff09;是一个开源的AI工具开发平台&#xff0c;提供了丰富的API和简单易用的界面&#xff0c;帮助用户快速搭建各种A…

AIGC时代——语义化AI驱动器:提示词的未来图景与技术深潜

文章目录 一、技术范式重构&#xff1a;从指令集到语义认知网络1.1 多模态语义解析器的进化路径1.2 提示词工程的认知分层 二、交互革命&#xff1a;从提示词到意图理解2.1 自然语言交互的认知进化2.2 专业领域的认知增强 三、未来技术图谱&#xff1a;2025-2030演进路线3.1 20…

【AI 大模型】LlamaIndex 大模型开发框架 ② ( LlamaIndex 可配置的 LLM 类型 | LlamaIndex 可配置的 文本向量模型 类型 )

文章目录 一、LlamaIndex 可配置的 LLM 类型1、云端 API 类型 LLM2、本地部署 类型 LLM3、混合部署 LLM4、错误示例 - 设置 云端 DeepSeek 大模型 二、LlamaIndex 可配置的 文本向量模型 类型1、云端 文本向量模型2、本地部署 文本向量模型3、适配器微调模型 AdapterEmbeddingM…

云端微光,AI启航:低代码开发的智造未来

文章目录 前言一、引言&#xff1a;技术浪潮中的个人视角初次体验腾讯云开发 Copilot1.1 低代码的时代机遇1.1.1 为什么低代码如此重要&#xff1f; 1.2 AI 的引入&#xff1a;革新的力量1.1.2 Copilot 的亮点 1.3 初学者的视角1.3.1 Copilot 带来的改变 二、体验记录&#xff…

OCR+AI双引擎驱动:手把手教学构建智能财报分析系统

在金融行业中&#xff0c;财报分析是帮助企业和投资者做出决策的关键环节。随着科技的快速发展&#xff0c;自动化、智能化的财报分析变得越来越重要。传统的人工财报分析不仅费时费力&#xff0c;而且容易受到人为错误的影响&#xff0c;因此企业急需借助先进的技术来提高效率…