我读过有关易失性(https://www.ibm.com/developerworks/java/library/j-jtp06197/)的文章,发现有一点说易失性写比非易失性写要昂贵得多。
我可以理解,与易失性写入相关的成本会增加,因为易失性写入是一种同步方式,但我想知道,一个易失性写入的代价如何比非易失性写入要高得多;它是否与生成易失性写入时不同线程堆栈之间的可见性有关?
发布于 2014-03-06 12:14:32
这就是为什么,根据你提到的那篇文章:
由于确保可见性所需的内存栅栏,易失性写入比非易失性写入要昂贵得多,但通常仍然比锁获取便宜。 ..。易失性读取很便宜--几乎和非易失性读取一样便宜。
当然,这是正确的:内存隔离操作总是绑定到写入和读取,不管底层变量是否易失性,执行方式都是相同的。
然而,Java中的volatile不仅仅是易失性和非易失性内存读取。实际上,它的本质与这种区别无关:区别在于并发语义。
考虑一下这个臭名昭著的例子:
volatile boolean runningFlag = true;
void run() {
while (runningFlag) { do work; }
}如果runningFlag不是volatile,JIT编译器实际上可以将代码重写到
void run() {
if (runningFlag) while (true) { do work; }
}不必说,在每次迭代中读取runningFlag所带来的开销与根本不读取它的比率是巨大的。
发布于 2014-03-06 12:10:47
它是关于缓存的。由于新的处理器使用缓存,如果不指定易失性数据,则保持在高速缓存中,并且写入操作非常快速。(由于缓存接近处理器)如果变量被标记为易失性,系统需要将其完全写入内存nad中,这样的操作要慢一些。
是的,您的想法是正确的,它必须使用不同的线程堆栈,因为每个线程堆栈是分开的,从相同的内存读取,但不一定从相同的缓存读取。今天,处理器使用许多级别的缓存,所以如果多个线程/进程使用相同的数据,这可能是一个大问题。
编辑:如果数据停留在本地缓存中,其他线程/进程将不会看到更改,直到数据被写回内存。
发布于 2014-03-06 12:11:07
最有可能的是,这与易失性写入必须阻塞管道这一事实有关。
所有写操作都排队等待写入缓存。在非易失性的写/读中,您不会看到这一点,因为代码可以只获得您刚刚编写的值,而不涉及缓存。
当您使用易失性读取时,它必须返回到缓存,这意味着写入下的写入(如已实现的)不能继续写入到这种情况下(如果您进行了一次写入,然后执行了一次读)。
一种方法是使用延迟写入,例如AtomicInteger.lazySet(),它比易失性写入快10倍,因为它不等待。
https://stackoverflow.com/questions/22223922
复制相似问题