【java双重检查锁定模式】

文章详细解释了Java中的双重检查锁定模式用于实现单例时的原理,强调了volatile关键字在确保线程间变量可见性的重要性。通过示例代码展示了如果没有volatile可能导致的问题,以及使用volatile后如何保证线程安全。同时提到了其他替代方案,如惰性初始化模式和final语义的应用。
摘要由CSDN通过智能技术生成

java双重检查锁定模式 双if判断


public class Singleton {
    private volatile static Singleton uniqueInstance;
    private Singleton() {}
    public static Singleton getInstance() {
    //5.此时线程T4进来,直接return对象
    //1. 假设T1,T2,T3 三个线程进入,都通过第一层if
        if (uniqueInstance == null) {
        //2.因为加了锁,此时只能进入一个,假设T2进入,T1、T3等待
            synchronized (Singleton.class) {
            //3.T2通过判断,成功返回
            //4.此时T1进入,发现pojo有值,不再new直接return前面创建好的pojo,T3类推
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}


// 这里的uniqueInstance为什么要使用volatile修饰???

/**
【维基百科解释】:
线程T2发现变量没有被初始化, 然后它获取锁并开始变量的初始化。
由于某些编程语言的语义,编译器生成的代码允许在线程T2执行完变量的初始化之前,更新变量并将其指向部分初始化的对象。
线程T1或者T3发现共享变量已经被初始化,并返回变量。由于线程B确信变量已被初始化,它没有获取锁。如果在A完成初始化之前共享变量对B可见(这是由于A没有完成初始化或者因为一些初始化的值还没有覆盖B使用的内存(缓存一致性)),程序很可能会崩溃。
*/

//================== 下面使用小段代码再次说明 ==================

/**
volatile 关键字的作用是保证变量在多线程之间的可见性,
即每次读取该变量的值时都会强制从主内存中读取。
下面是一个使用 volatile 关键字和不使用的例子:
*/
public class VolatileTest {
    private static volatile boolean flag = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (!flag) {
            }
            System.out.println("Thread1 finished.");
        }).start();

        Thread.sleep(1000);

        new Thread(() -> {
            flag = true;
            System.out.println("Thread2 finished.");
        }).start();
    }
}

/**
在上面的例子中,如果不使用 volatile 关键字,那么线程1将永远无法结束,
因为它无法感知到线程2对变量的修改。
但是,如果使用了 volatile 关键字,那么线程1将会感知到线程2对变量的修改并结束1
*/



//这段代码中,有兴趣的朋友也可以测试一下
//局部变量result的使用看起来是不必要的。对于某些版本的Java虚拟机,这会使代码提速25%,
//而对其他的版本则无关痛痒。
class Foo {
    private volatile Helper helper = null;
    public Helper getHelper() {
        Helper result = helper;
        if (result == null) {
            synchronized(this) {
                result = helper;
                if (result == null) {
                    helper = result = new Helper();
                }
            }
        }
        return result;
    }
}

//如果说获取的对象为静态修饰,还可以使用【惰性初始化模式】来替代,有兴趣可以自行上网搜索

//final语义可以不使用volatile关键字实现安全的创建对象 有兴趣可以自行上网搜索

//最后,类似单例模式,或者一些对应的业务,需要我们保证在并发时只生产一份的情况下,我们可以使用该方式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值