了解Java中同步化块与易变变量的原子性,可见性和重新排序 [英] Understanding atomic-ness, visibility and reordering of synchonized blocks vs volatile variables in Java

查看:90
本文介绍了了解Java中同步化块与易变变量的原子性,可见性和重新排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从《 Java并发实践》一书中理解volatile关键字.我在三个方面将synchronized关键字与volatile变量进行了比较:原子性,波动性和重新排序.我对此有一些怀疑.我在下面逐一讨论了它们:

I am trying to understand volatile keyword from the book Java Concurrency in Practice. I compares synchronized keyword with volatile variables in three aspects: atomic-ness, volatility and reordering. I have some doubts about the same. I have discussed them one by one below:

关于synchronized的可见性,书说如下:

Book says following with respect to visibility of synchronized:

B在执行由同一锁保护的同步块时,对B可见在同步块中或之前执行的所有线程.

Everything thread A did in or prior to a synchronized block is visible to B when it executes a synchronized block guarded by the same lock.

关于volatile变量的可见性,其内容如下:

It says following with respect to visibility of volatile variables:

易失性变量不会缓存在寄存器中或对其他处理器隐藏的缓存中,因此对易失性变量的读取总是返回任何线程的最新写入.
易失性变量的可见性影响超出了 易失变量本身.当线程A写入易失性变量,随后线程B读取相同的变量时,在读取易失性变量后,在写入易失性变量之前A可见的所有变量的值对B都是可见的.因此,从内存可见性的角度来看,写入volatile变量就像退出同步块,而读取volatile变量就像进入同步块.

Volatile variables are not cached in registers or in caches where they are hidden from other processors, so a read of a volatile variable always returns the most recent write by any thread.
The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the volatile variable become visible to B after reading the volatile variable. So from a memory visibility perspective, writing a volatile variable is like exiting a synchronized block and reading a volatile variable is like entering a synchronized block.

第一季度.我觉得上面第二段(volatile)与书中关于synchronized的说法相对应.但是,synchronized是否等同于volatile的第一段?换句话说,使用synchronized是否可以确保任何/某些变量不会被缓存在处理器缓存和寄存器中?

Q1. I feel second paragraph above (of volatile) corresponds to what book said about synchronized. But is there synchronized-equivalent to volatile's first paragraph? In other words, does using synchronized ensures any / some variables not getting cached in processor caches and registers?

请注意,该书还介绍了有关synchronized的可见性的信息:

Note that book also says following about visibility for synchronized:

锁定不仅涉及互斥;这也与内存可见性有关.

Locking is not just about mutual exclusion; it is also about memory visibility.

2)重新排序:`synchornized`与`volatile`

Book在重新排序的上下文中对volatile说了以下内容:

2) Reordering: `synchornized` vs `volatile`

Book says following about volatile in the context of reordering:

当一个字段声明为volatile时,将通知编译器和运行时该变量是共享的,并且对该变量的操作不应与其他内存操作重新排序.

When a field is declared volatile, the compiler and runtime are put on notice that this variable is shared and that operations on it should not be reordered with other memory operations.

第二季度.书中没有提到在synchronized上下文中重新排序的任何内容.有人可以解释在synchronized上下文中可以说的重新排序吗?

Q2. Book does not say anything about reordering in the context of synchronized. Can someone explain what can be said of reordering in the context of synchronized?

Book说到synchronizedvolatile的原子性.

Book says following about atomicity of synchronized and volatile.

volatile的语义尚不足以使增量操作(count++)原子化,除非可以保证仅从单个线程写入变量.

the semantics of volatile are not strong enough to make the increment operation (count++) atomic, unless you can guarantee that the variable is written only from a single thread.

锁定可以保证可见性和原子性.易变变量可以 仅保证可见性.

Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility.

Q3.我想这意味着两个线程可以同时看到volatile int a,两个线程都将其递增然后保存.但是只有最后一次读取才有效,因此使整个读取增量保存"成为非原子的.我对volatile的非原子性的这种解释正确吗?

Q3. I guess this means two threads can see volatile int a together, both will increment it and then save it. But only one last read will have effect, thus making whole "read-increment-save" non atomic. Am I correct with this interpretation on non-atomic-ness of volatile?

第四季度.是否所有等效的锁都具有可比性,并且具有相同的可见性,有序性和原子性:同步块,原子变量,锁?

Q4. Does all locking-equivalent are comparable and have same visibility, ordering and atomicity property: synchronized blocks, atomic variables, locks?

PS:此问题与

PS: This question is related to and completely revamped version of this question I asked some days back. Since its full revamp, I havent deleted the older one. I wrote this question in more focused and structured way. Will delete older once I get answer to this one.

推荐答案

'synchronized'和'volatile'之间的主要区别在于,'synchronized'可以使线程暂停,而volatile则不能.

The key difference between 'synchronized' and 'volatile', is that 'synchronized' can make threads pause, whereas volatile can't.

缓存和注册"不是问题.该书说,因为在实践中通常是事情的实现方式,并且这使得(如果有这些问题的话)更容易理解(也许不是).为什么使用JMM(Java内存模型).

'caches and registers' isn't a thing. The book says that because in practice that's usually how things are implemented, and it makes it easier (or perhaps not, given these questions) to understand the how & why of the JMM (java memory model).

但是,JMM没有为其命名.它只是说说VM可以自由地给每个线程自己的任何变量的本地副本,以便在任意时间与某些或所有其他线程进行同步,或者不同步... 除非 >任何地方都存在事前发生的关系,在这种情况下,VM 必须确保在建立了发生关系的两个线程之间的执行点,他们观察到所有处于相同状态的变量.

The JMM doesn't name them, however. All it says is that the VM is free to give each thread its own local copy of any variable, or not, to be synchronized at some arbitrary time with some or all other threads, or not... unless there is a happens-before relationship anywhere, in which case the VM must ensure that at the point of execution between the two threads where a happens before relationship has been established, they observe all variables in the same state.

在实践中,这大概意味着刷新缓存.或不;这可能意味着另一个线程将覆盖其本地副本.

In practice that would presumably mean to flush caches. Or not; it might mean the other thread overwrites its local copy.

VM可以自由地实现其所需的东西,并且在每个架构上都有不同的实现.只要VM坚持JMM做出的保证,它就是一个很好的实现,因此,您的软件必须在仅提供这些保证的前提下才能工作,而没有其他假设.因为如果您依靠JMM不能保证的假设,那么您机器上的有效内容可能就不会在其他机器上有效.

The VM is free to implement this stuff however it wants, and differently on every architecture out there. As long as the VM sticks to the guaranteed that the JMM makes, it's a good implementation, and as a consequence, your software must work given solely those guarantees and no other assumptions; because what works on your machine might not work on another if you rely on assumptions that aren't guaranteed by the JMM.

重新排序也不在VM规范中. VM规范中的IS是以下两个概念:

Reordering is also not in the VM spec, at all. What IS in the VM spec are the following two concepts:

  1. 在单个线程的范围内,您可以从内部观察到的所有内容均与有序视图一致.也就是说,如果您写'x = 5; y = 10;'从同一线程中无法观察到y为10,而x为其旧值.不论是同步的还是易变的.因此,只要它可以在无法观察的情况下对事物进行重新排序,那么虚拟机就可以自由使用.会吗由虚拟机决定.有的有,有的没有.

  1. Within the confines of a single thread, all you can observe from inside it is consistent with an ordered view. That is, if you write 'x = 5; y = 10;' it is not possible to observe, from within the same thread, y being 10 but x being its old value. Regardless of synchronized or volatile. So, anytime it can reorder things without that being observable, then the VM is free to. Will it? Up to the VM. Some do, some don't.

当观察由其他线程引起的影响,并且尚未建立事前发生的关系时,您可能会以任何顺序看到这些影响中的一些,全部或没有.真的,这里什么都可以发生.在实践中,那么:在未建立事件之前,请勿尝试观察由其他线程引起的影响,因为结果是任意的且 unestable .

When observing effects caused by other threads, and you have not established a happens-before relationship, you may see some, all, or none of these effects, in any order. Really, anything can happen here. In practice, then: Do NOT attempt to observe effects caused by other threads without establishing a happens-before, because the results are arbitrary and untestable.

发生各种事情之前发生的关系;同步块显然可以做到这一点(如果您的线程在试图获取锁的过程中被冻结,然后运行,该对象上任何完成了之前发生"的同步块,以及您现在可以观察到的所有内容,并保证了您所执行的操作观察与按顺序运行的那些东西以及它们写入的所有数据可以看到的位置一致(例如,您将不会获得较旧的缓存"或诸如此类的东西).易失性访问也是如此.

Happens-before relationships are established by all sorts of things; synchronized blocks obviously do it (if your thread is frozen trying to acquire a lock, and it then runs, any synchronized blocks on that object that finished 'happened before', and anything they did you can now observe, with the guarantee that what you observe is consistent with those things having run in order, and where all data they wrote you can see (as in, you won't get an older 'cache' or whatnot). Volatile accesses do as well.

是的,即使x是易失性的,对于x ++不是原子的,您的解释也是正确的.

Yes, your interpretation of why x++ is not atomic even if x is volatile, is correct.

我不确定您第四季度想问什么.

I'm not sure what your Q4 is trying to ask.

通常,如果要原子地递增整数,或执行许多其他并发式操作中的任何一种,请查看java.util.concurrent程序包.这些包含各种概念的有效和有用的实现. AtomicInteger 可用于以原子方式递增某些内容,这种方式可以从其他线程看到,同时仍然非常高效(例如,如果您的CPU支持Compare-And-Set( CAS)操作,Atomicinteger会使用它;如果不诉诸Unsafe,则不是一般Java所能做的事情.

In general, if you want to atomically increment an integer, or do any of many other concurrent-esque operations, look at the java.util.concurrent package. These contain efficient and useful implementations of various concepts. AtomicInteger, for example, can be used to atomically increment something, in a way that is visible from other threads, while still being quite efficient (for example, if your CPU supports Compare-And-Set (CAS) operations, Atomicinteger will use it; not something you can do from general java without resorting to Unsafe).

这篇关于了解Java中同步化块与易变变量的原子性,可见性和重新排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆