首页 > 代码库 > 并发——关键字volatile
并发——关键字volatile
本段内容均来自于《Thinking in Java》并发一章的内容,作为阅读的笔记或者可以理解为抄书。
原子性是可以用于除long和double之外的所有基本类型的“简单操作”。对于读取和写入除long和double之外的基本类型这样的操作,可以保证他们会被当做不可分割的操作来操作内存。但是对于long和double这种64位(long和double在Java中都占用64位)的数据,JVM在操作的时候会把他分成2个32位的来操作,这样在这中间就可能会发生读取和写入操作的上下文切换,从而导致看到不是你希望的结果(称为字撕裂)。当你使用volatile定义long和double的时候会获得原子性(注意在Java SE5.0之前,volatile一直没有正确的工作)。不同的JVM可以提供更强的保证,但你最好不要依赖平台性。
volatile关键字还确保了应用中的可视性。如果你把一个域声明为volatile的,只要你对这个域做了写操作,那么所有的读取操作都能够看到这个修改。即使使用了本地缓存,情况也是如此,因为volatile域会被立即写到主存中,而读取操作就发生在主存中。
理解原子性和易变性是不同的概念很重要,在非volatile域上的原子操作不必刷新到主存中去,因此其他读取操作也不必看到这个新值。如果多个任务同时访问一个域的话,那么这个域应该设为volatile的,或者应该使用synchronized同步方法来保护,synchronized也能将数据刷新到主存当中去。一个任务所有的写入操作对于自己本身都是可视的,所以当只有一个任务的时候就没有必要使用volatile关键字。
当一个值依赖于他之前的值得时候(比如计算器),volatile就无法工作了。如果这个域受到其他域的限制,那么volatile也无法工作,例如Range类的lower和upper边界就必须遵循lower<=upper。
使用volatile而不是synchronized唯一安全的的情况下就是类中只有一个可变域。再次提醒,你的第一选择应该是synchronized关键字,这是最安全的方式,而其他任何尝试都是有风险的。
并发——关键字volatile