Java中primitive type的线程安全性
Java中primite type,如char,integer,bool之类的,它们的读写操作都是atomic的,但是有几个例外:
- long和double类型不是atomic的,因为long和double都是8字节的,而在32位的CPU上,其机器字长为32位,操作8个字节需要多个指令操作。
- ++i或者i++,因为要先读后写,也是多步操作。
这些情况下,需要使用AutomicInteger,AutomicLong。
同时,java中的reference的读写也是automic的,虽然reference到底占几个字节没有明确定义,但至少以下可以保证:
- 在32位的CPU下,使用的是4字节的reference
- 在64位的CPU下,可以使用4字节或者8字节的reference
所以无论如何,对reference的操作肯定是单步操作,是automic的。
事实上,一个蛮有用的例子是cache switch - 你有两个cache pool,分别用两个reference指向:cache_in_build和cache_in_use,等cache_in_build完成了,你需要把cache_in_use指向它,没有问题,这是线程安全的。
但是问题是,jvm可以会reorder你的statement:
- cache_in_build.build()
- cache_in_use = cache_in_build
期望是cache在build完了之后,切换过去。
但是这两行代码并没有前后的dependency关系,所以JVM可以为了优化,进行乱序执行,变成:
- cache_in_use = cache_in_build
- cache_in_build.build()
于是,如果另一个线程在使用cache_in_use,在代码#1执行完之后,就访问到了正在build的那个cache,这是个问题。
解决方案是cache_in_use必须定义为volatile,保证happen-before的关系,拒绝乱序执行,从而保证其他线程看到的数据是有效的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?