Java中的volatile关键词(可见性、禁止指令重排、单例模式)

目录

一、volatile变量的特性

1、保证可见性,不保证原子性

可见性?

不保证原子性?

2、禁止指令重排

二、单例模式(双重检查锁)


一、volatile变量的特性

参考:

volatile为什么不能保证原子性?_Ludwig__的博客-CSDN博客_volatile为什么不能保证原子性https://blog.csdn.net/qq_46190347/article/details/109908724Java volatile关键字最全总结:原理剖析与实例讲解(简单易懂)_老鼠只爱大米的博客-CSDN博客_java volatilehttps://blog.csdn.net/u012723673/article/details/80682208?spm=1001.2014.3001.5506

1、保证可见性,不保证原子性

可见性?

(1)读volatile:每当子线程某一语句要用到volatile变量时,都会从主线程重新拷贝一份,这样就保证子线程的会跟主线程的一致。
(2)写volatile: 每当子线程某一语句要写volatile变量时,都会在读完后同步到主线程去,这样就保证主线程的变量及时更新。

不保证原子性?

仅在单次读或者单次写这样的原子操作中,volatile能够实现线程安全。如果遇到 i++ 这种复合操作时(i++ 复合了读取、加、赋值3步),不能保证原子性。

2、禁止指令重排

(1)当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行;

(2)在进行指令优化时,不能将对volatile变量访问的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行。

什么是指令重排?参考:

java排序为什么会出现多次排序结果不一样_并发理论基础:指令重排序问题_向天再借十厘米的博客-CSDN博客https://blog.csdn.net/weixin_29734285/article/details/113083692?spm=1001.2014.3001.5506【Java 并发编程】指令重排序规范 ( happens-before 先行发生原则 )_韩曙亮的博客-CSDN博客_java指令重排序https://hanshuliang.blog.csdn.net/article/details/120186485?spm=1001.2014.3001.5506

二、单例模式(双重检查锁)

参考:

单例模式----双重检查锁_迪迪didi的博客-CSDN博客_单例模式双重校验锁https://blog.csdn.net/weixin_50005657/article/details/115803998?spm=1001.2014.3001.5506例子:

(这属于懒汉模式,初次使用时才实例化。【饿汉模式:一开始就实例化】)

public class TestInstance {
    private volatile TestInstance instance;

    public TestInstance getInstance() {
        //1
        if (instance == null) {
            //2
            synchronized (this) {
                //3
                if (instance == null) {
                    //4
                    instance = new TestInstance();
                }
            }
        }
        //6
        return instance;
    }
}

为什么要用同步锁synchronized就不赘述了,重点讲解为什么要用volatile?

步骤//4能被拆解成如下伪代码:

a.分配内存
memory = allocate() 

b.初始化对象
ctorInstanc(memory)

c.设置instance指向刚分配的地址
instance = memory

如果instance不被volatile修饰,伪代码中abc指令可能会被重排序。假设有两个线程A和B,线程A先执行,执行到步骤//4时,指令被重排序成acb,线程A执行完指令c后,instance已经有指向的地址,instance不再为空,但该对象还未被初始化。此时,线程B执行,在步骤//1时,判断instance不为空,直接返回一个未被初始化的对象instance。综上所述,volatile可以用来防止指令重排序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java实现一个线程安全且能优异的单例模式可以使用双重检查锁定(Double-Checked Locking)机制。具体的实现代码如下: ```java public class Singleton { private volatile static Singleton instance; private Singleton() { // 私有化构造方法,防止外部创建实例 } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } ``` 在上述代码,通过将 `instance` 声明为 `volatile` 关键字,确保了多个线程对 `instance` 变量进行操作时的可见。双重检查锁定机制的思路是,在实例创建之前先进行两次判断,这样可以减少不必要的同步开销提高能。 需要注意的是,在 Java 5 以前的版本,使用双重检查锁定机制可能会出现线程安全问题,因为 Java 5 以前的版本volatile 关键字的语义不够强,可能会出现指令重排导致的问题。所以,建议在 Java 5 或更高版本使用双重检查锁定机制。 此外,还可以使用静态内部类的方式实现线程安全且能优异的单例模式。具体的实现代码如下: ```java public class Singleton { private Singleton() { // 私有化构造方法,防止外部创建实例 } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } } ``` 通过将实例的创建放在静态内部类,可以保证在需要使用时才会创建实例,并且通过类加载机制保证了线程安全。这种方式也是推荐的单例模式实现方式之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cyc头发还挺多的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值