JVM 伪共享

伪共享False sharing说明JVM底层技术也不让人那么放心。

内存缓存系统中基本单元是高速缓存行(Cache lines). cpu会把数据从内存加载到高速缓存中 ,这样可以获得更好的性能,高速缓存默认大小是64 Byte为一个区域,一个区域在一个时间点只允许一个核心操作,也就是说不能有多个核心同时操作一个缓存区域。

因为高速缓存是64字节,而Hotspot JVM的对象头是两个部分组成,第一部分是由24字节的hash code和8字节的锁等状态标识组成,第二部分是指向该对象类的引用。基本类型字节如下:
doubles (8) and longs (8)
ints (4) and floats (4)
shorts (2) and chars (2)
booleans (1) and bytes (1)
references (4/8)

因此,一个高速缓存64字节可以放下多个字段,如果这多个字段位于同一个高速缓存区,虽然它们是类的不同字段,如下代码:
Class A{
   int x;
   int y;
}

x和y被放在同一个高速缓存区,如果一个线程修改x;那么另外一个线程修改y,必须等待x修改完成后才能实施。

虽然两个线程修改各种独立变量,但是因为这些独立变量被放在同一个高速缓存区,性能就影响了。测试结果如后面。

当多核CPU线程同时修改在同一个高速缓存行各自独立的变量时,会不自不觉地影响性能,这就发生了伪共享False sharing,伪共享是性能的无声杀手。

解决方便是将高速缓存剩余的字节填充填满(pad),确保不发生多个字段被挤入一个高速缓存区,下面测试结果图就是和填充后性能比较。

实现字节填充的框架有 Disruptor,在RingBuffer中实现填充。关于Disruptor可见infoQ这个视频,用1毫秒的延时得到100K+ TPS吞吐量,JDK的ArrayQueue并行环境不见得是最快的,该视频后面讨论很多,让人大跌眼镜啊,开放源码多有好处啊,别人能发现你不能发现的漏洞。另外一篇解剖Disruptor


C#也有类似伪共享发生,见这里




原文地址: http://www.jdon.com/42451
### JVM 中多线程实现原理 JVM 的多线程机制主要依赖于操作系统的线程模型以及 Java 虚拟机自身的调度能力。在 JVM 中,每启动一个应用程序都会创建一个主线程来执行 `main` 方法[^2]。除此之外,JVM 还会自动创建其他辅助线程,比如垃圾回收线程用于管理和释放不再使用的内存资源。 #### 线程的生命周期 Java 中的线程具有明确定义的生命周期,包括新建 (New)、就绪 (Runnable)、运行 (Running)、阻塞 (Blocked) 和终止 (Terminated) 阶段。这些状态由操作系统和 JVM 协同管理,确保线程能够高效切换并完成其任务。 #### 线程同步与锁机制 为了处理并发访问共享资源的问题,JVM 提供了内置的同步工具,例如 **synchronized 关键字** 和 **ReentrantLock 类**。当多个线程尝试修改同一份数据时,可以通过加锁的方式防止冲突。具体来说: - 使用 synchronized 块可以保护特定代码片段不被多个线程同时进入。 - ReentrantLock 则提供了更灵活的功能,允许显式锁定和解锁操作,并支持超时等待等功能。 #### 内存可见性和 Volatile 关键字 由于 CPU 缓存的存在,在多核处理器环境下可能会发生指令重排序现象,从而导致某些变量更新无法及时反映到其他线程中。为此,引入了 volatile 关键字标记那些需要立即刷新至主存中的字段,强制保证不同线程间对该字段的操作具有一致性[^3]。 ```java // 示例:volatile 变量声明 public class SharedResource { private volatile boolean flag = false; public void setFlag(boolean value){ this.flag = value; } public boolean getFlag(){ return this.flag; } } ``` ### 常见问题分析 以下是关于 JVM线程的一些典型疑问及其解答: 1. **死锁如何预防?** 死锁通常发生在两个或更多线程互相持有对方所需的资源而陷入僵持局面。为了避免这种情况的发生,建议按照固定的顺序获取锁;或者采用 try-lock 方式代替传统 lock/unlock 流程。 2. **什么是共享(Pseudo-sharing)? 如何优化?** 当相邻缓存行上的独立变量频繁被不同的核心读写时可能引发性能下降即所谓的共享效应。解决方案之一是对齐布局敏感型成员变量使其分布远离彼此减少干扰。 3. **ThreadLocal 是什么作用?** ThreadLocal 为每个使用该类的对象维护了一份副本存储空间使得即使存在竞争条件也能保持各自的数据隔离不受影响。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值