第三章 Java内存模型之volatile⑥
接上一章Java内存模型之顺序一致性,我们来理解下volatile。
了解volatile特性,一个好方法就是把volatile变量的单个读、写 ,可以看成是使用同一个锁对这些单个读/写进行了同步。
class demo{volatile long v1 = 0L;public void set(long l){v1 = l;}public long get(){return v1;}}class demo{ long v1 = 0L;public synchronized void set(long l){v1 = l;}public synchronized long get(){return v1;}}上面的两段代码效果是一样的。
我们都知道锁的 happens-before 规则来保证释放锁和获取锁的两个线程之间的内存可见性。所以意味着一个 volatile 变量的读,总是能看到(任意线程)对这个 volatile 变量的最后写入。
锁的语义决定了临近区代码的执行具备原子性,即便64位的 long 或者者 double 变量,只需是 volatile 变量,那么该变量的读/写就具备原子性。但是多个 volatile 操作或者者 volatile++ 是不具备原子性的。
volatile 具备以下特性:
1)可见性。 对一个 volatile 变量的读,总是能看到(任意线程)对这个 volatile 变量的最后写入。
2)原子性。对任意的那个 volatile 变量的读/写都具备原子性。但是相似于 volatile++ 不具有。
对于程序员来说,volatile 对线程的内存可见性影响比 volatile 自身的特性更重要。volatile 的读/写可以实现线程之间的通信。
比照锁的释放-取得对内存的影响,volatile 也具备相同的内存语义。volatile 读==锁的获取。volitle 写 == 锁的释放。
当写一个 volatile 变量时,JMM 会把该线程对应的本地内存中的共享变量值刷新到主内存中。
当读取一个 volatile 时,JMM 会把该线程对应的本地内存置为无效,而后从主内存中读取共享变量。
总结一下 volatile 的读/写:
1)线程 A 写一个 volatile 变量,实际上是线程 A 向接下来将要读这个 volatile 变量的某个线程发出来(其对共享变量所做的修改的)消息。
2)线程 B 读一个 volatile 变量,实际上是线程 B 接收了之前某个线程发出的(在写这个 volatile 变量之前对这个共享变量修改的)消息。
3)程序 A 写一个 volatile 变量,随后程序 B 读这个 volatile 变量,这个过程实质上就是线程 A 通过主内存向线程 B 发送消息。
其实也印证了我们之前所说的共享内存的通信是隐性的。
为了实现 volatile ,JMM限制了编译器和解决器的重排序。
重排序规则
总结一下这个规则:
1、当第二个操作是 volatile 写的时候,不论第一个操作是啥,都不允许重排序。确保 volatile 写之前的操作不会被编译器重排序到 volatile 写之后。
2、当第一个操作是 volatile 读的时候,不论第二个操作是啥,都不允许重排序。确保 volatile 读之后的操作不会被编译器重排序到 volatile 读之前。
3、当都是两个都是 volatile 操作的时候,不允许重排序。
所以总结顺口溜: 1读2写3一律,全都不许重排序。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 第三章 Java内存模型之volatile⑥