解决原子性问题?脑海中有这个模型就可以了

针对MCP协议通信的降熵洞察:WebSocket JSON-RPC 无法满足模型上下文管理需求 本文深入分析了传统WebSocket+JSON-RPC组合在AI 2.0应用中的局限性,指出其在处理动态性强的MCP协议时会产生严重的"语义漂移"问题。通过建立数学模型和实测数据,揭示了传统方案在逻辑一致性、状态对齐和事务隔离等方面的致命缺陷。文章提出采用MCP协议的解决方案,其通过事务原子化寻址、状态校验快照等机制,将逻辑误差从12.5%降至10^-7级别。实战案例和性能对比显示,MCP方案在吞吐量、故障恢复和系统稳定性等方面均有显著提升,为AI通讯协议提供了更可靠的底层架构。 阅读详情

原子性问题的源头就是 线程切换,但在多核 CPU 的大背景下,不允许线程切换是不可能的,正所谓「魔高一尺,道高一丈」,新规矩来了:

互斥: 同一时刻只有一个线程执行

实际上,上面这句话的意思是: 对共享变量的修改是互斥的,也就是说线程 A 修改共享变量时其他线程不能修改,这就不存在操作被打断的问题了,那么如何实现互斥呢?

01 锁

对并发有所了解的小伙伴马上就能想到 锁 这个概念,并且你的第一反应很可能就是使用 synchronized,这里列出来你常见的 synchronized 的三种用法:

public class ThreeSync {

	private static final Object object = new Object();

	public synchronized void normalSyncMethod(){
		//临界区
	}

	public static synchronized void staticSyncMethod(){
		//临界区
	}

	public void syncBlockMethod(){
		synchronized (object){
			//临界区
		}
	}
}

三种 synchronized 锁的内容有一些差别:

  • 对于普通同步方法,锁的是当前实例对象,通常指 this
  • 对于静态同步方法,锁的是当前类的 Class 对象,如 ThreeSync.class
  • 对于同步方法块,锁的是 synchronized 括号内的对象

我特意在三种 synchronized 代码里面添加了「临界区」字样的注释,那什么是临界区呢?

临界区: 我们把需要互斥执行的代码看成为临界区

说到这里,和大家串的知识都是表层认知,如何用锁保护有效的临界区才是关键,这直接关系到你是否会写出并发的 bug,了解过本章内容后,你会发现无论是隐式锁/内置锁 (synchronized) 还是显示锁 (Lock) 的使用都是在找寻这种关系,关系对了,一切就对了,且看

上面锁的三种方式都可以用下图来表达:

                                                 

线程进入临界区之前,尝试加锁 lock(), 加锁成功,则进入临界区(对共享变量进行修改),持有锁的线程执行完临界区代码后,执行 unlock(),释放锁。针对这个模型,大家经常用抢占厕所坑位来形容:

                                        

在学习 Java 早期我就是这样记忆与理解锁的,但落实到代码上,我们很容易忽略两点:

  1. 我们锁的是什么?
  2. 我们保护的又是什么?

将这两句话联合起来就是你的锁能否对临界区的资源起到保护的作用?所以我们要将上面的模型进一步细化

                    

现实中,我们都知道自己的锁来锁自己需要保护的东西 ,这句话翻译成你的行动语言之后你已经明确知道了:

  1. 你锁的是什么
  2. 你保护的资源是什么

CPU 可不像我们大脑这么智能,我们要明确说明我们锁的是什么,我们要保护的资源是什么,它才会用锁保护我们想要保护的资源(共享变量)

拿上图来说,资源 R (共享变量) 就是我们要保护的资源,所以我们就要创建资源 R 的锁来保护资源 R,细心的朋友可能发现上图几个问题:

LR 和 R 之间有明确的指向关系 我们编写程序时,往往脑子中的模型是对的,但是忽略了这个指向关系,导致自己的锁不能起到保护资源 R 的作用(用别人家的锁保护自己家的东西或用自己家的锁保护别人家的东西),最终引发并发 bug,所以在你勾画草图时,要明确找到这个关系

左图 LR 虚线指向了非共享变量 我们写程序的时候很容易这么做,不确定哪个是要保护的资源,直接大杂烩,用 LR 将要保护的资源 R 和没必要保护的非共享变量一起保护起来了,举两个例子来说你就明白这么做的坏处了

  1. 编写串行程序时,是不建议 try...catch 整个方法的,这样如果出现问是很难定位的,道理一样,我们要用锁精确的锁住我们要保护的资源就够了,其他无意义的资源是不要锁的
  2. 锁保护的东西越多,临界区就越大,一个线程从走入临界区到走出临界区的时间就越长,这就让其他线程等待的时间越久,这样并发的效率就有所下降,其实这是涉及到锁粒度的问题,后续也都会做相关说明

作为程序猿还是简单拿代码说明一下心里比较踏实,且看:

public class ValidLock {
	
	private static final Object object = new Object();
	
	private int count;
	
	public synchronized void badSync(){
		//其他与共享变量count无关的业务逻辑
		count++;
	}
	
	public void goodSync(){
		//其他与共享变量count无关的业务逻辑
		synchronized (object){
			count++;
		}
	}
}

这里并不是说 synchronized 放在方法上不好,只是提醒大家用合适的锁的粒度才会更高效

在计数器程序例子中,我们会经常这么写:

public class SafeCounter {

	private int count;

	public synchronized void counter(){
		count++;
	}

	public synchronized int getCount(){
		return count;
	}
}

下图就是上面程序的模型展示:

                                                 

这里我们锁的是 this,可以保护 this.count。但有些同学认为 getCount 方法没必要加 synchronized 关键字,因为是读的操作,不会对共享变量做修改,如果不加上 synchronized 关键字,就违背了我们上一篇文章 happens-before 规则中的监视器锁规则:

对一个锁的解锁 happens-before 于随后对这个锁的加锁 也就是说对 count 的写很可能对 count 的读不可见,也就导致脏读

上面我们看到一个 this 锁是可以保护多个资源的,那用多个不同的锁保护一个资源可以吗?来看一段程序:

public class UnsafeCounter {

	private static int count;

	public synchronized void counter(){
		count++;
	}

	public static synchronized int calc(){
		return count++;
	}
}

睁大眼睛仔细看,一个锁的是 this,一个锁的是 UnsafeCounter.class, 他们都想保护共享变量 count,你觉得如何?下图就是行面程序的模型展示:

原子性,多锁一个资源.png

                              

两个临界区是用两个不同的锁来保护的,所以临界区没有互斥关系,也就不能保护 count,所以这样加锁是无意义的

02 总结

  1. 解决原子性问题,就是要互斥,就是要保证中间状态对外不可见
  2. 锁是解决原子性问题的关键,明确知道我们锁的是什么,要保护的资源是什么,更重要的要知道你的锁能否保护这个受保护的资源(图中的箭头指向)
  3. 有效的临界区是一个入口和一个出口,多个临界区保护一个资源,也就是一个资源有多个并行的入口和多个出口,这就没有起到互斥的保护作用,临界区形同虚设
  4. 锁自己家门能保护资源就没必要锁整个小区,如果锁了整个小区,这严重影响其他业主的活动(锁粒度的问题)

本文以 synchronized 锁举例来说明如何解决原子性问题,主要是帮助大家建立宏观的理念,用于解决原子性问题,这样后续你看到无论什么锁,只要脑海中回想起本节说明的模型,你会发现都是换汤不换药,学习起来就非常轻松了.

到这里并发的三大问题 有序性,可见性,原子性都有了解决方案,这是远看并发,让大家有了宏观的概念;但面试和实战都是讲求细节的,接下来我们由远及近,逐步看并发的细节,顺带说明那些面试官经常会问到的问题

 

深入解析流水线技术:从基本概念到冒险问题的实战解决方案 本文深入解析流水线技术,从基本概念到冒险问题的实战解决方案。通过介绍CPU流水线的工作原理、性能优化方法和三大冒险问题(结构冒险、数据冒险、控制冒险),帮助读者全面理解流水线技术在计算机体系结构中的应用与优化策略。 阅读详情

相关推荐

【netty】 io.netty.handler.codec.TooLongFrameException

背景 做netty权威指南的私有协议开发,案例报错如 io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 1048576: 795898487 - discarded at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(Lengt...

九师兄 2万+

Seata 一次入坑异常

在启动SEATA之后,运行官方samples时候,后台始终报错。io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 8388608: 2415945472 - discarded 究其原因是Seataclient与SeataServer版本不一致导致。好大的坑。 ...

sizheshen的博客 6709

LangGraph实战:用Python异步构建智能客服多轮对话系统(附完整代码)

本文详细介绍了如何使用LangGraph框架和Python异步编程构建一个高性能的智能客服多轮对话系统。通过将对话流程建模为有向图,结合thread_id实现多用户对话隔离,并利用异步节点提升系统并发处理能力,有效解决了传统客服系统上下文遗忘与高并发瓶颈问题。文章提供了从环境搭建、状态管理、异步优化到复杂业务逻辑与部署的完整实战代码。

weixin_29055137的博客 152

原子性问题

原子性问题 现在咱们来看并发编程中第二个问题,原子性问题。那么咱们的目标学习什么是原子性问题?在学习的过程中,咱们分成两步,第一步介绍原子性的概念,第二步通过一个案例来演示原子性问题。 咱们先来看原子性的概念,我们也是要先看一下前提,首先第一个啊也是要有多个线程,如果一个县城没有竞争是看不出问题的。第二我们要有共享变量,到时候多个线程来对共享变量操作。 原子性是指在一次或多次操作中,要么所有的操作都执行并且不会受其他因素的干扰而中断,要么所有的操作都不执行。 案例: 目标:演示原子性问题 步骤: 1、定义一

qq_38991247的博客 954

【若依(ruoyi)】BootstrapTable列宽定制实战:突破width属性限制的两种方案

本文针对若依(RuoYi)框架中BootstrapTable组件列宽设置失效的常见问题,提供了两种实战解决方案。通过CSS样式覆盖法强制定义列宽,或利用formatter函数进行动态HTML包裹,有效突破width属性限制,实现精准的表格列宽定制。

weixin_29013129的博客 175

群晖Web Station实战:从零搭建个人静态导航站

本文详细介绍了如何利用群晖NAS自带的Web Station套件,从零开始搭建个人静态导航站。通过安装Web Station、上传静态网站源码、配置网页服务与网络门户等步骤,无需代码基础即可实现内网访问。文章还分享了文件权限设置、个性化定制及常见问题排查等实用技巧,帮助用户高效管理个人常用网址,充分挖掘NAS的服务器潜能。

tea88的博客 1330

Adjusted frame length exceeds 4096: 5637 - discarded 服务端解决

解决服务端Adjusted frame length exceeds 4096: 5637 - discarded问题1. 具体错误2. 错误原因3. 解决方法 1. 具体错误 下面展示一些 错误详情。 io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 4096: 18247 - discarde...

weixin_44055686的博客 2万+

用C#和MQTTnet在WinForm里做个简易物联网监控后台(附完整源码)

本文详细介绍了如何使用C#和MQTTnet库在WinForm中构建一个简易物联网监控后台。通过实战案例,包括环境配置、MQTT服务端实现、客户端监控功能及高级优化技巧,帮助开发者快速搭建高效的物联网监控系统,适用于工业自动化和智能家居场景。

weixin_29540599的博客 393

Java线程面试题:什么是原子性问题?如何解决?

在 Java 5 中,Java 并发包提供了更加高效的 Atomic 类型,如 AtomicInteger、AtomicLong 等,它们提供了一些原子操作方法,例如 incrementAndGet()、decrementAndGet() 等,可以更加便利地解决原子性问题。原子性问题是指在并发编程中,多个线程同时访问共享资源时,可能会出现某些操作因为被中断而执行不完整,导致数据出错等问题。但实际上运行多次后,每次的输出结果都可能不同,并且通常都小于20000,这是由于这个例子存在原子性问题所导致的。

jakelihua 331

HSM 网络安全 信息安全

HSM HSM信息安全功能 汽车电子网络安全中HSM 的应用场景 选择适合汽车电子网络安全的 HSM 符合汽车安全标准和法规要求的HSM HSM 在汽车电子网络安全中的可靠性和安全性 评估汽车电子网络的安全性 汽车 HSM(Hardware Security Module)模块开发 汽车 HSM(Hardware Security Module)模块测试

天赐好车的博客 1240

一文看懂 SAP Integration Suite:从架构治理、接口编排到事件驱动的集成全景

SAP Integration Suite是企业数字化转型中的关键集成平台,通过统一的方法论和工具链解决系统互联、数据对齐和流程协同等复杂问题。其核心能力包括:1)集成评估(Integration Assessment)提供战略规划框架;2)迁移评估(Migration Assessment)支持从传统平台向云的平滑过渡;3)云集成(Cloud Integration)实现日常业务流程编排;4)集成顾问(Integration Advisor)简化B2B标准映射;5)贸易伙伴管理(TPM)优化外部协作流程;

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 505

Java内存模型是什么?

当我们提到Java内存模型(Java Memory Model,简称JMM)时,我们脑海中可能首先会浮现出堆、栈、方法区和程序计数器等,但其实这些概念不是Java内存模型,这些概念是Java内存区域。要了解Java内存模型,我们先说一下它解决了什么问题,JMM是一种规范,它解决了Java并发中多线程通过共享内存进行通讯时,存在的本地内存数据不一致以及编译器指令重排带来的一些问题。简单点说就是JMM规范了程序中变量的访问规则,保障了并发操作的原子性、可见性和有序性的问题。

冥胖胖9的博客 480

RK3588上使用PCIE接口的国产千兆网卡YT6801

YT6801是裕太微电子开发的一款国产千兆PCIE以太网控制器芯片,可作为RK3588的PCIE外扩网口使用。

荻夜的博客 8223

JUC_3_共享模型之管程(java并发编程)

共享带来的问题、synchronized、线程八锁、变量的线程安全分析...

柴柴的博客 3620

Python爬虫-爬取汽车之家各品牌周销量榜数据,进行数据分析

本文是该专栏的第57篇,后面会持续分享python爬虫干货知识。本文中,笔者已经整理20篇汽车平台相关的爬虫项目案例。对此感兴趣的同学,可以直接翻阅查看。同样,笔者在本文中将继续以汽车之家平台为例子。基于Python爬虫,实现批量爬取“各品牌周销量榜单”的数据。废话不多说,具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。接下来,跟着笔者直接往下看正文详细内容。(附带完整代码)

Python进阶专栏《爬虫实战进阶》,《Pyppeteer从入门到精通》原创作者 366

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

不再迷惑的Java内存模型

一直以来,java内存模型都是让人很迷惑的东西,很多书籍,博客都有对它的相关介绍,很多人读完后,还是搞不清楚。而且这个东西和JVM的内存结构又很容易混淆,很多博客讲解内存模型都会当成JVM的内存结构去讲,甚至我身边有着好几年java工作经验的人,都搞不明白,说一些堆,虚拟机栈啥的。所以呢,今天就和读者一起来探究java内存模型到底是什么东西。这个模型是干嘛用的。 一说到模型,我相信很多人脑海中就...

进步的阶梯的博客 252

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

线程不安全 静态变量_不一样的视角:从JVM内存模型谈线程安全

作者:江湖人称小白哥链接:https://blog.youkuaiyun.com/dd864140130/article/details/58359102存储器层次结构对于开发者来说,存储器的层次结构应该是非常熟悉的,大体如下:其中寄存器,L1,L2,L3都被封装在CPU芯片中,作为应用开发者而言我们很少去注意和使用它.之所以引入L1,L2,L3高速寄存器,其根本是为了解决访问运算器和内存速度不...

weixin_39632524的博客 127

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

该线程尝试读写某个虚拟地址_从架构师的角度谈谈:JVM内存模型线程安全

存储器层次结构对于开发者来说,存储器的层次结构应该是非常熟悉的,大体如下:其中寄存器,L1,L2,L3都被封装在CPU芯片中,作为应用开发者而言我们很少去注意和使用它.之所以引入L1,L2,L3高速寄存器,其根本是为了解决访问运算器和内存速度不匹配.但缓存的引入也带来两个问题:缓存命中率:缓存的数据都是主存中数据的备份,如果指令所需要的数据恰好在缓存中,我们就说缓存命中,反之,需要从主存中获取.一...

weixin_39843698的博客 418

【并发编程JUC】共享导致的问题、synchronized语法

共享导致的问题、临界区、竞态条件、synchronized语法、线程八锁。

See_Star的博客 658

从JMM内存模型谈内存安全(转载)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.youkuaiyun.com/dd864140130/article/details/58359102 作为一个三个多月没有去工作的独立开发者而言,今天去小米面试了一把.怎么说呢,无论你水平如何,请...

欧阳能达 245

Java并发(十三)----共享存在的问题

一个程序运行多个线程本身是没有问题的 问题出在多个线程访问共享资源 多个线程读共享资源其实也没有问题 在多个线程对共享资源读写操作时发生指令交错,就会出现问题 一段代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区

263

关于线程的心得一

最近对自己近一年的工作状态总结了一下, 感觉自己的忙碌并没有真正的换来自己计划中想要的,我应该是一个知道并且是明确知道自己想要的是什么得人,但是从工作到现在走来,每天都在加班工作、学习,但是自己手里拿到的,脑海中想到的都不是真正属于我的,甚至在很多技术面前没有足够的了解,但是工作终归是工作,我不能不负责任,然后看着映入眼帘的满屏的代码,意识里面告诉自己,这套系统我还没有完全熟悉,应该将它好好的看一...

qq_37104276的博客 240

并发复习笔记

CPU缓存行:64bytes 几种常见的概念 内核空间与用户空间:针对于内存来划分的 内核态与用户态:针对于CPU来划分的 KLT与ULT:针对于线程的管理工作是由内核去完成还是程序自己完成来划分 并发三大特性: 原子性:一个或多个操作,要么全部执行,要么全部不执行,synchronized/lock 可见性:一个线程修改共享变量,其他线程可以看到修改的值,volatile(MESI) 有序性:因为存在指令重排(编译器,CPU)程序执行顺序要按照代码先后顺序执行,volatile(内存屏障..

曾的左的博客 176
上一篇: 公司要求每天做操20分钟,程序员回答:打断写代码思路谁来负责?
下一篇: 百度员工年薪50万被朋友怼:根本不羡慕,我一年创业比你挣多得多
加班不秃顶
博客等级 码龄7年 1822粉丝 599原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值