您的位置:首页 > 教育 > 锐评 > 【JUC】11-volatile关键字

【JUC】11-volatile关键字

2024/10/5 23:01:34 来源:https://blog.csdn.net/qq_45722630/article/details/141828713  浏览:    关键词:【JUC】11-volatile关键字

1. volatile关键字修饰变量特点

 不支持原子性。

  • 可见性:对一个被volatile关键字修饰的变量,1. 写操作,这个变量的最新值会立即刷新回到主内存中。 2. 读操作,总是能够读取到这个变量的最新值,也就是这个变量最后被修改的值。 3. 当某个线程收到通知,去读取volatile修饰的变量的值的时候,线程私有工作内存的数据失效,需要重新回到主内存中读取最新的数据。
  • 有序性:有时需要禁止重排序。

2. volatile内存语义

  • 当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值立即刷新回主内存中。
  • 当读一个volatile变量时,JMM会把该线程对应的本地内存设置为无效,重新回到内存中读取最新共享变量。
  • 所以volatile的写内存语义是直接刷新到主内存中,读的内存语义是直接从内存中读取。

3. volatile内存屏障

写屏蔽:写屏蔽之前的所有写操作都要写回到主内存。
读屏蔽:读屏蔽之后的所有读操作都在读屏蔽之后执行,都可以读到最新数据。在这里插入图片描述

4. 指令重排

在这里插入图片描述

5. volatile的可见性

public class demo04 {/* volatile 可以让数据将线程中的数据副本更新到主内存中去掉 volatile, 子线程中的 flag 会一直自己的数据副本, 不会进行更新*/static volatile boolean flag = true;public static void main(String[] args) {new Thread(()->{System.out.println("thread start");while (flag) {}System.out.println("exit");}).start();try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}flag = false;System.out.println("flag update: "+flag);}
}

 volatile加锁与解锁的过程。在这里插入图片描述

6. volatile无原子性

 volatile不能保证同一时刻,对于同一份数据,只有一个线程操作。volatile适合与布尔类型和int类型。
 一下i++的例子证明volatile无原子性。

class Number {// 使用volatile结果输出并不稳定唯一volatile int num;public void add() {num ++;}public int get(){return num;}
}public class demo05 {public static void main(String[] args) {Number number = new Number();for(int i=0; i<10; i++) {new Thread(()->{for (int j = 0; j < 100; j++) {number.add();}}).start();}try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(number.get());}
}

7. volatile禁止重排

双重检查锁定(Double-Checked Locking, DCL)的单例模式:

public class SafeDoubleCheckSingleton {private static volatile SafeDoubleCheckSingleton singleton;private SafeDoubleCheckSingleton() {}public static SafeDoubleCheckSingleton getInstance() {if (singleton == null) {synchronized (SafeDoubleCheckSingleton.class) {if (singleton==null) {/*** singleton 实例化:分配内存空间、初始化对象、将对象指向分配的内存空间* JMM 可能会进行指令重排: 分配内存空间、将对象指向分配的内存空间、初始化对象* 多线程场景下, 会出现问题* 为 singleton 添加 volatile 关键字, 可解决这个问题*/singleton = new SafeDoubleCheckSingleton();}}}return singleton;}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com