Java 与非易失性写入相比,易失性写入的成本增加
我一直在读关于volatile()的书,发现有一点说volatile写比非volatile写要昂贵得多Java 与非易失性写入相比,易失性写入的成本增加,java,performance,volatile,Java,Performance,Volatile,我一直在读关于volatile()的书,发现有一点说volatile写比非volatile写要昂贵得多 我可以理解,如果volatile是一种同步方式,那么与volatile写入相关的成本会增加,但我想知道volatile写入比非volatile写入贵多少;这可能与进行易失性写入时不同线程堆栈之间的可见性有关吗?这是关于缓存的。由于新处理器使用缓存,若不指定,易失性数据将保留在缓存中,并且写入操作很快。(因为缓存在处理器附近)若变量被标记为易失性,系统需要将其完全写入内存nad,这是一个稍微慢一
我可以理解,如果volatile是一种同步方式,那么与volatile写入相关的成本会增加,但我想知道volatile写入比非volatile写入贵多少;这可能与进行易失性写入时不同线程堆栈之间的可见性有关吗?这是关于缓存的。由于新处理器使用缓存,若不指定,易失性数据将保留在缓存中,并且写入操作很快。(因为缓存在处理器附近)若变量被标记为易失性,系统需要将其完全写入内存nad,这是一个稍微慢一点的操作 是的,您的想法是正确的,它必须使用不同的线程堆栈,因为每个线程堆栈都是独立的,从相同的内存读取,但不一定从相同的缓存读取。今天,处理器使用多个级别的缓存,因此如果多个线程/进程使用相同的数据,这可能是一个大问题
编辑:如果数据保留在本地缓存中,则在将数据写回内存之前,其他线程/进程不会看到更改 这很可能与易失性写入必须暂停管道这一事实有关 所有写入都排队写入缓存。对于非易失性写/读,您看不到这一点,因为代码可以在不涉及缓存的情况下获取您刚刚编写的值 当您使用volatile read时,它必须返回缓存,这意味着写操作(如已实现)无法在写操作已写入案例(如果先写后读)的情况下继续
解决这一问题的一种方法是使用惰性写入,例如AtomicInteger.lazySet(),它可以比易失性写入快10倍,因为它不需要等待。以下是原因,根据您指出的文章: 易失性写操作比非易失性写操作的成本要高得多,因为保证可见性所需的内存限制,但通常仍比锁获取便宜 […]易失性读取很便宜——几乎和非易失性读取一样便宜 当然,这是正确的:内存围栏操作总是以相同的方式执行写操作和读操作,而不管底层变量是否易变 然而,
volatile
在Java中不仅仅是volatile和非volatile内存读取。事实上,本质上它与这种区别无关:区别在于并发语义
以这个臭名昭著的例子为例:
volatile boolean runningFlag = true;
void run() {
while (runningFlag) { do work; }
}
如果runningFlag
不是volatile
,JIT编译器基本上可以将该代码重写为
void run() {
if (runningFlag) while (true) { do work; }
}
不用说,每次迭代读取
runningFlag
与根本不读取它所带来的开销之比是巨大的。非常松散(考虑到Peter和DjDexter5GHz提到的分布式缓存):非常松散(考虑到@Peter和@DjDexter5GHz提到的关于分布式缓存的位):runningFlag
位于主内存的堆上;更改为runningFlag
意味着写入主内存,然后根据需要写入辅助和三级内存,然后再次从(most)加载runningFlag
三级内存还是主内存?是否会为每次写入不同内存位置构建一个内存围栏,或者是主内存中的一个内存围栏,在该围栏下协调对runningFlag
的所有值的更新?而且runningFlag
的每次易失性读取都意味着至少一次或多次写入三级/二级内存即使主内存中的runningFlag
保持不变,也会存储大量内存?因此,volatile的成本似乎是基于这样一个事实,即需要更多的指令来精确保证,但底层内存和处理器体系结构(特别是现代多核处理器体系结构)也起着重要作用至于volatile的成本?您的理解还不够。例如,在Intel CPU体系结构上,根本不需要内存围栏,因为CPU本身可以保证正确的可见性和写入顺序。因此,它只是一条mov
指令,而在不同的体系结构上,它最多需要一个额外的内存nce指令。我不理解你的推理,你说“volatile read意味着至少一次写入”。不意味着写入,只是普通RAM读取(同样是x86上的单个mov
指令)根据我的理解,lazySet
实际上完全满足了volatile
的要求。区别在于写入的可视性的及时性,这对于volatile
是未指定的。如果其他线程同时可以看到写入,那么lazySet的不同之处在于它可能不会是的,volatile
:每个人都认为写的东西会立即可见(或同步可见,以使这个概念更具实质性)是的,lazySet
提供了完全相同的东西,只是延迟可能更长。因此,lazySet
的语义完全符合volatile write的语义,依我看lazySet
的奇怪之处在于:它意味着volatile
不仅仅是一个问题,实际上不是。我指的是volatile
和lazySet
的特定语义,所以这个参数是通用的。