Volatile关键字问题总结
‼️该变量的所有更新操作对所有线程都是可见的
1. 作用:
1️⃣ 保证可见性,线程修改volatile变量后,其他线程能立即看到最新值。(可见性)
2️⃣ 防止指令重排,volatile变量的写入不会被重排序到它之前的代码。(有序性)
2. 如何保证可见性?
线程对volatile变量进行写操作时,JVM会在这个变量后插入一个写屏障指令,强制本地内存中的变量值刷新到主内存中。
线程对volatile变量进行读操作时,JVM会插入一个读屏障指令,换个指令会强制让本地内存中的变量值失效,重新从主内存中读取最新的值。
E.g. 线程A写入volatile变量,该变量被写入主内存中;线程B从本地内存中读取该变量,失效,要从主内存中读取该变量最新的值。
3. 如何保证有序性?
普通读
普通写
——————
StoreStore 禁止上面的普通写和下面的volatile写的重排
——————
volatile写
——————
StoreLoad 禁止下面的volatile读和volatile写的重排
——————
volatile读
——————
LoadLoad 禁止上面的volatile读和下面的普通读的重排
——————
——————
LoadStore 禁止下面的volatile读和下面的普通写的重排
——————
普通读
普通写
4. volatile在汇编语言层面是怎么实现的
在汇编语言层面,💡volatile 主要是通过在写操作后添加一个带有 lock 前缀的指令来实现的。
这个 lock 前缀有两个核心作用:
✨它充当了内存屏障,防止了指令重排序。
它会触发硬件的缓存一致性机制(如 MESI),强制将修改后的数据刷入主存,并让其他 CPU 缓存中的该数据失效,从而保证了可见性。
5. volatile和synchronized的区别?
volatile:该变量的所有更新操作对所有线程都是可见的。
synchronized:确保同一时刻只有一个线程能够执行该方法或代码块,实现互斥访问
6. volatile和synchronized的实现原理?
volatile 的实现:主要靠汇编层面的 lock 前缀指令。它充当了💡内存屏障,强制把修改后的值刷回主存并让其他缓存失效,从而解决可见性和有序性问题。
synchronized 的实现:synchronized 依赖 💡JVM 内部的 Monitor 对象来实现线程同步。使用的时候不用手动去 lock 和 unlock,JVM 会自动加锁和解锁。
synchronized 加锁代码块时,JVM 会通过 monitorenter 、 monitorexit 两个指令来实现同步:
前者表示线程正在尝试获取 lock 对象的 Monitor; 后者表示线程执行完了同步代码块,正在释放锁。
使用 javap -c -s -v -l SynchronizedDemo.class 反编译 synchronized 代码块时,就能看到这两个指令。 synchronized 修饰普通方法时,JVM 会通过 ACC_SYNCHRONIZED 标记符来实现同步。
1. 作用:
1️⃣ 保证可见性,线程修改volatile变量后,其他线程能立即看到最新值。(可见性)
2️⃣ 防止指令重排,volatile变量的写入不会被重排序到它之前的代码。(有序性)
2. 如何保证可见性?
线程对volatile变量进行写操作时,JVM会在这个变量后插入一个写屏障指令,强制本地内存中的变量值刷新到主内存中。
线程对volatile变量进行读操作时,JVM会插入一个读屏障指令,换个指令会强制让本地内存中的变量值失效,重新从主内存中读取最新的值。
E.g. 线程A写入volatile变量,该变量被写入主内存中;线程B从本地内存中读取该变量,失效,要从主内存中读取该变量最新的值。
3. 如何保证有序性?
普通读
普通写
——————
StoreStore 禁止上面的普通写和下面的volatile写的重排
——————
volatile写
——————
StoreLoad 禁止下面的volatile读和volatile写的重排
——————
volatile读
——————
LoadLoad 禁止上面的volatile读和下面的普通读的重排
——————
——————
LoadStore 禁止下面的volatile读和下面的普通写的重排
——————
普通读
普通写
4. volatile在汇编语言层面是怎么实现的
在汇编语言层面,💡volatile 主要是通过在写操作后添加一个带有 lock 前缀的指令来实现的。
这个 lock 前缀有两个核心作用:
✨它充当了内存屏障,防止了指令重排序。
它会触发硬件的缓存一致性机制(如 MESI),强制将修改后的数据刷入主存,并让其他 CPU 缓存中的该数据失效,从而保证了可见性。
5. volatile和synchronized的区别?
volatile:该变量的所有更新操作对所有线程都是可见的。
synchronized:确保同一时刻只有一个线程能够执行该方法或代码块,实现互斥访问
6. volatile和synchronized的实现原理?
volatile 的实现:主要靠汇编层面的 lock 前缀指令。它充当了💡内存屏障,强制把修改后的值刷回主存并让其他缓存失效,从而解决可见性和有序性问题。
synchronized 的实现:synchronized 依赖 💡JVM 内部的 Monitor 对象来实现线程同步。使用的时候不用手动去 lock 和 unlock,JVM 会自动加锁和解锁。
synchronized 加锁代码块时,JVM 会通过 monitorenter 、 monitorexit 两个指令来实现同步:
前者表示线程正在尝试获取 lock 对象的 Monitor; 后者表示线程执行完了同步代码块,正在释放锁。
使用 javap -c -s -v -l SynchronizedDemo.class 反编译 synchronized 代码块时,就能看到这两个指令。 synchronized 修饰普通方法时,JVM 会通过 ACC_SYNCHRONIZED 标记符来实现同步。
全部评论
相关推荐
02-02 19:45
厦门理工学院 Java 点赞 评论 收藏
分享
