yas*_*ash 12 c# java multithreading volatile multiprocessing
C#和Java都定义
*volatile读取具有获取语义
*volatile写入具有发布语义
我的问题是:
- 这是定义volatile的唯一正确方法吗?
- 如果没有,如果语义被颠倒,事情就会大不相同,也就是说
- volatile读取具有释放语义
- volatile写入具有获取语义
Kon*_*che 13
volatile语义背后的原因植根于Java内存模型,它是根据操作指定的:
Java内存模型为Java程序中可能发生的操作定义了一个名为happen-before的部分排序.通常无法保证线程可以看到每个其他操作的结果.
比方说,你有两个动作一个和乙.为了保证执行动作B的线程可以看到动作A的结果,A和B之间必须存在先发生关系.否则,JVM可以随意对它们进行重新排序.
未正确同步的程序可能会有数据争用.当一个变量被> 1个线程读取并由> = 1个线程写入时,会发生数据争用,但读取和写入操作不是通过发生前的排序来排序的.
因此,正确同步的程序没有数据争用,程序内的所有操作都按固定顺序发生.
所以行动通常只是部分订购,但也有一个总订单:
这些行动是完全有序的.
这使得在"后续"锁定获取和易失性变量读取方面描述发生之前是明智的.
关于你的问题:
volatile
这说明了当两个线程使用公共锁同步时发生在之前的关系.线程A中的所有操作都按程序顺序规则排序,线程B中的操作也是如此.因为A释放锁定M而B 随后获取M,因此在释放锁定之前A中的所有操作都在B中的操作之前排序获得锁定后.当两个线程在不同的锁上同步时,我们不能说它们之间的动作顺序,在两个线程中的动作之间没有发生 - 之前的关系.
来源:实践中的Java并发
获取/释放语义的强大之处不在于其他线程多久能够看到易失性字段本身的新写入值,而在于易失性操作在不同线程之间建立先发生关系的方式.如果线程A读取volatile字段并且看到在另一个线程B中写入该字段的值,那么线程A也保证在线程B执行之前看到线程B 写入其他(不一定是易失性)变量的值.易失写.这看起来像缓存刷新,但仅从读取volatile的线程的角度来看,其他不接触volatile字段的线程没有关于B的排序保证,并且可能会看到一些早期的非易失性写入但是如果编译器/ JIT如此倾向,则不是其他人.
监视器获取/释放的特征类似于它们引发的先发生关系 - 在监视器释放之前,一个线程的动作保证在另一个线程后续获取同一监视器之后可见.Volatiles为您提供与监视器同步相同的排序保证,但不会阻塞.