单例模式的写法(保证线程安全)

在这里插入图片描述

什么是单例模式

**单例模式(SingLeton)**是一种经典的设计模式(大佬们总结出来的代码编写套路)
单例模式能保证某个类在程序中只存在唯一一份实例, 而不会创建出多个实例, 防止频繁地创建对象使得内存飙升,让所有需要调用的地方都共享这一单例对象。

1. 饿汉模式(安全)

在类加载时已经创建好该单例对象,等待被程序使用
(天然安全的,仅只是读取了变量的内容)

class Singleton {
    //私有化,只能在类内部创建对象
    private static Singleton instance = new Singleton();

    //向外提供一个公共的静态方法,用于外部引用该对象
    public static Singleton getInstance() {
        return instance;
    }

    //禁止外部 new 实例
    private Singleton(){};
}
public class TestDemo1 {
    public static void main(String[] args) {
        //此时S1 与 S2 是同一个对象
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();

        //Singleton s3 = new Singleton();//报错

    }

}

2. 懒汉模式(危险)

先不创建,在真正需要使用对象时才去创建该单例类对象

代码演示:

public class Singleton {
 
    // 提供一个对象的引用
    private static Singleton instance = null;
 
    // 防止外部new对象
    private Singleton(){}
 
    // 用于创建对象或使得外部能够访问到创建的对象
    public static Singleton getInstance(){
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

(不安全,有读也有写,并发环境下很可能出现多个Singleton实例):
如:两个线程t1,t2同时进入该方法,需要返回给 t1 ,t2 对象实例。当 t1 进入该方法后,进行判断,不为 null,因此需要创建一个对象,而在创建对象的过程中,此时t2 刚好也进入了该方法,也被判断成了不为 null,此时,t1, t2就指向不同的对象了,所以它是线程不安全的。

解决办法

  1. 加锁,在线程1工作时避免线程2进入创建对象
class SingletonLazy {
    private static SingletonLazy instance = null;

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

但加锁会使程序堵塞,运行速度变慢

  1. 双重 if ,判断 instance 是否被初始化完成
class SingletonLazy {
    private static SingletonLazy instance = null;

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

    private SingletonLazy(){}
}
public class TestDemo2 {
    public static void main(String[] args) {
        SingletonLazy s1 = SingletonLazy.getInstance();
        SingletonLazy s2 = SingletonLazy.getInstance();
        System.out.println(s1 = s2);

    }

}
  1. 再使用 volatile 禁止指令重排序,防止编译器优化,保证后续线程肯定拿到是完整对象
 private static volatile SingletonLazy instance = null;
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值