Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 与非易失性写入相比,易失性写入的成本增加_Java_Performance_Volatile - Fatal编程技术网

Java 与非易失性写入相比,易失性写入的成本增加

Java 与非易失性写入相比,易失性写入的成本增加,java,performance,volatile,Java,Performance,Volatile,我一直在读关于volatile()的书,发现有一点说volatile写比非volatile写要昂贵得多 我可以理解,如果volatile是一种同步方式,那么与volatile写入相关的成本会增加,但我想知道volatile写入比非volatile写入贵多少;这可能与进行易失性写入时不同线程堆栈之间的可见性有关吗?这是关于缓存的。由于新处理器使用缓存,若不指定,易失性数据将保留在缓存中,并且写入操作很快。(因为缓存在处理器附近)若变量被标记为易失性,系统需要将其完全写入内存nad,这是一个稍微慢一

我一直在读关于volatile()的书,发现有一点说volatile写比非volatile写要昂贵得多


我可以理解,如果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
的特定语义,所以这个参数是通用的。