volatile、synchronized、final内存语义

volatile内存语义

  1. 当写volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。
  2. 当读volatile变量时,volatile变量的每次使用都必须从主内存刷新最新的值。

JMM针对编译器对编译器指定的volatile重排序规则表

是否能重排序第二个操作
第一个操作普通读/写volatile读volatile写
普通读/写NO
volatile读NONONO
volatile写NONO

当第二个操作为volatile写,不管第一个操作是什么都不能进行重排序。确保volatile写之前的操作不会被编译器重排序到volatile写之后。

当第一个操作位volatile读,不管第二个操作是什么都不能进行重排序。确保volatile读之后的操作不会被编译器重排序到volatile读之前。

当第一个操作是volatile写,第二个操作是volatile读或者volatile写时不能重排序。语义

为了实现volatile的内存语义,编译器在生成字节码时,会在指令序列插入内存屏障来禁止特定类型的处理器重排序。下面是基于JMM内存屏障插入策略:

  • 在每个volatile写操作的前面插入一个StoreStore屏障
  • 在每个volatile写操作的后面插入一个StoreLoad屏障
  • 在每个volatile读操作的后面插入一个LoadLoad屏障
  • 在每个volatile读操作的后面插入一个LoadStore屏障

volatile写插入内存屏障指令序列示意图

普通读
普通写
StoreStore屏障(禁止上面的普通写与下面的volatile写重排序)
volatile写
StoreLoad屏障(禁止上面的volatile写与下面可能有的volatile读/写重排序)

volatile读插入内存屏障指令序列示意图

volatile读
LoadLoad屏障(禁止下面的普通读和上面的volatile读重排序)
LoadStore屏障(禁止下面的普通写和上面的volatile读重排序)
普通读
普通写

synchronized内存语义

锁可以让临界区互斥执行。

当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。

当线程获取锁时,JMM会把该线程对应的本地内存置为无效。从而使得被监视器保护的临界区代码必须从主内存中读取共享变量。

线程A释放锁,实质上是线程A向接下来将要获取这个锁的某个线程发出了(线程A对共享变量所做修改的)消息。

线程B获取锁,实质上是线程B接收了之前某个线程发出的(在释放这个锁之前对共享变量所做修改的)消息。

线程A释放锁,随后线程B获取锁,这个过程实质上是线程A通过主内存向线程B发送消息。

释放锁与volatile写有相同的内存语义,获取锁与volatile读有相同的内存语义。

final内存语义

public class FinalTest {
    int i;
    final int j;
    static FinalTest obj;
    public FinalTest() {
        i = 1;
        j = 2;
    }
    public static void write() {
        obj = new FinalTest();
    }
    public static void read() {
        FinalTest object = obj;
        int a = object.i;
        int b = object.j;
    }
}

写final域的重排序规则禁止把final域的写重排序到构造函数之外。这个规则可以保证,在对象引用为任意线程可见之前,对象的final域已经被正确初始化过了,而普通域不具有这个保证。

读final域的重排序规则是:在一个线程中,初次读对象引用与初次读对象包含的final域,JMM禁止重排序这两个操作。这个规则可以保证,在读一个对象的final域之前,一定会先读包含这个final域的对象的引用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值