单例模式的线程安全写法

什么是单例模式?

所谓单例模式就是一种经典设计模式,关键要点是借助java语法保证某个类只能够创建出一个实例,而不能再通过构造方法new出多个实例。在java中,单例模式有很多种写法,本文只探讨了经典的“饿汉模式”和“懒汉模式”两种写法

注意:

如果用洗碗来做类比的话,吃完饭立刻就去洗碗这个就是属于“饿汉模式”的范畴,相反如果等到下次再使用碗的时候才开始洗碗这就是“懒汉模式”的范畴,类比于创建实例,“饿汉模式”就是提前把这个实例创建好不管之后会不会去使用,而“懒汉模式”则是非必要不创建实例

1.基于饿汉模式实现线程安全的单例模式:

package threading;
class Singleton{
    private static Singleton instance=new Singleton();//唯一实例的本体
    public  static Singleton getInstance(){
        return instance;
    }
    private Singleton(){//把这个构造方法用private修饰,禁止外部new实例

    }
}
public class ThreadDemo13 {
    public static void main(String[] args) {
        Singleton s1=Singleton.getInstance();
        Singleton s2=Singleton.getInstance();
        //Singleton s3=new Singleton();//这里就会报错·
    }

}

注解:

1.此时的饿汉模式就是天生的线程安全,因为在SingleTon的getInstance方法中只设计了return instance这个操作,也就是只有读取操作所以在多线程同时执行的时候也是线程安全的

2.以上代码是如何实现单例模式的呢?就是用private修饰SingleTon内部的构造方法,让在类外面无法通过new来创建实例

3.在main方法里面创建的s1和s2实例本质上是一个对象,这也是单例模式的内涵体现,但是如果使用new SingleTon来创建实例就会报错

2.基于懒汉模式实现线程安全的单例模式:

class SingletonLazy{
    private static SingletonLazy instance=null;//先置为null,需要创建的时候再创建
    public static SingletonLazy getInstance(){
       
                if (instance == null) {
                    instance = new SingletonLazy();
                }
            
        
        return instance;
    }
    private SingletonLazy(){//保证不能再在外部new

    }
}

“懒汉模式”是线程不安全的,有读也有写(解决办法1.加锁,把if和new变成原子操作2.双重if,减少不必要的加锁操作3.使用volatile关键字禁止指令重排序,保证后续线程拿到的是完整对象)

原因:

(1)if里面的判空和new操作不是原子的

解决方案:给这个方法整体部位使用synchronize加锁

但是根据“非必要不加锁”的准则,此处的线程不安全只出现在首次创建对象(new)这里,一旦对象new好了后续调用getinstance就只是单纯的读操作,就没有线程安全问题了,就没有必要再加锁了 ,所以以上代买可以加一个判定条件(看是否是首次创建对象,如果不是首次创建那么就直接返回这个实例)

(2)会出现指令重排序的问题

上面new对象的操作可以分为   1.分配对象空间   2. 实例化对象   3. 把对象的引用返回栈三个步骤,如果在多线程并发执行的时候可能因为编译器优化,把上面三个步骤顺序打乱也就是会出现指令重排序,类比装修房子,就是说t1线程如果房子还没有装修完就交给了t2线程那么t2线程拿到的就是一个清水房。

解决方案:使用volatile关键字去修饰这个instance

综上所述“懒汉模式”的正确代码如下:

class SingletonLazy{
    volatile private static SingletonLazy instance=null;//先置为null,需要创建的时候再创建
    public static SingletonLazy getInstance(){
        if(instance==null) {
            synchronized (SingletonLazy.class) {//加锁位置
                if (instance == null) {
                    instance = new SingletonLazy();
                }
            }
        }
        return instance;
    }
    private SingletonLazy(){//保证不能再在外部new

    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

四川网友机器猫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值