单例模式 (懒汉式, 线程同步详解)

单例模式(懒汉式)

在懒汉式写法中, 我们需要非常注意线程同步的问题. 大概有一下几个:
1. getInstance() 直接锁方法好不好
2. 双重锁定
3. synchronized(this)行不行

1. getInstance() 直接锁方法好不好

这种写法:

class Singleton {
    private static Singleton instance;
    private Singleton(){}

    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

我们可以看到这里synchronized是锁方法, 当两个线程都要进入getInstance()时, 只有一个能进入, 并创建出实例, 然后另外一个进入后, 判断 instace不为null, 然后直接得到instance. 这种做法是没有错误的. 但是由于线程都需要通过getInstance()来获取对象, 所以getInstance()调用频率很高, 所以线程被锁的频率也很高, 所以这种做法效率低.

2. 双重锁定

由于上面效率的原因, 你可能就会想到把 syschronized 放在 getInstance()里面, 这种可避免在调用getInstance()时的阻塞问题, 如下:

class Singleton {
    private static Singleton instance;
    private Singleton(){}

    public static Singleton getInstance(){
        if(instance == null){
            synchronized(Singleton.class){
                instance = new Singleton();
            }
        }
        return instance;
    }
}

这种写法看似没有问题, 其实却有一个很大的隐患, 在于: 如果两个线程同时执行getInstance(),判断 instance都不为null后, 进入if判断语句. 这个时候一个线程获得锁, 然后进入new了一个对象, 并开心的执行完了. 这个时候另外一个线程获得了锁, 但让它也不会再去判断 instace是否为null, 所以它也会再执行一次new操作. 所以这里执行了两次new操作. 当然最后instance还是只指向后一次new的对象.
所以这个时候需要双重锁定, 就是在 synchronized中再加一次 null判断, 如下:

class Singleton {
    private static Singleton instance;
    private Singleton(){}

    public static Singleton getInstance(){
        if(instance == null){
            synchronized(Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

这样就可以保证不会new两次, 也是相对比较正确的, 并且效率也很高.

3. synchronized(this)行不行

答案是不行的, 如果你写代码看一看, 直接就提示语法错误了, 因为我们的 getInstance() 方法是 static的, 所以里面不能使用 this.

好了以上三点终结, 希望对大家有帮助.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值