单例设计模式

89 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情

前言

之前经常听说一些设计模式,比如工厂模式,代理模式,单例模式等,但是一直都是听说,没有太多了解。直到突然遇到了。。。。

3B76F8E99BE7E8A356C5CB077771E0E8.gif 49967340F12FFD9A5799B4EC0A0DA5B9.gif

概念

设计模式:通过百度我们可以看到这样的解释

image.png

提取关键点,反复使用,经验总结。

说人话就是套路,模板

519385E4674EE85E11D379793AFFEC06.jpg

单例设计模式:

image.png

里面的核心就是:只new一次对象实例。

这么才能只new一次? 当然是:🤔构造器私有化,这样其他类就不能访问构造器,不能进行new操作了。 但是👀:在咱类内部,还是可以访问,然后其他类只能访问调用该类的某静态方法来返回创建当前类对象,静态方法只能访问静态变量。所以俺们把类内部产生的对象的变量,定义成静态的。

image.png 👌👍要实现单例设计模式,创建的类需要满足以下 3 个条件:

  1. 构造方法私有。
  2. 用一个私有的,静态引用类型实例变量。
  3. 提供一个公有的,静态方法来获得该实例。 4E6CEF3B06B13A4B86E53998B3B28165.jpg

单例模式1------懒汉式

🤔 那什么叫懒汉式呢?

懒汉式就是延迟加载,所谓延迟加载就是调用提供公共的静态的方法时实例才被创建出来。

比如创建一个独立的类xx,声明一个私有静态变量 s,提供一个私有构造方法,提供一个公共的静态返回对象方法。方法里面,如果s为null,就new一个对象赋给s,如果s存在,就直接返回 实现代码如下:👇

class Singleton1{
    // 私有的静态的引用类型变量
    private static Singleton1 s;

    // 私有的构造器
    private Singleton1(){

    }

    // 公共的静态的可返回该类的实例
    public static Singleton1 getInstance(){
        if(s == null){
            s = new Singleton1();
        }
        return s;
    }
}

我们可以设计一个test类

Singleton1 s1 = Singleton1.getInstance(); 
System.out.println(s1); 
Singleton1 s2 = Singleton1.getInstance(); 
System.out.println(s2); 
System.out.println(s1 == s2);

然后看看结果。(从结果中看到,两个对象打印的地址完全相同。) 412AE603644F0A7C4E4B8B9F2887E2EA.jpg

单例模式2------饿汉式

🤔 那什么叫饿汉式呢?

饿汉式就是立即加载,所谓立即加载就是使用该类的时候先将对象创建,不管以后会不会使用到该对象。

创建一个独立类xx2,声明一个私有静态最终的常量 s,初始化new一次。(因为这里已经new了,所以final修饰,不让修改之类的)提供一个私有的,无参构造方法。外部不能通过 new 创建对象;提供一个公共的静态的返回对象方法。

实现代码如下:👇

class Singleton2{

    // 私有的静态的最终的的引用类型的对象
    private static final Singleton2 S = new Singleton2();

    // 私有构造器
    private Singleton2(){

    }

    // 公共的静态的可返回该类的实例
    public static Singleton2 getInstance(){
        return S;
    }
}

同理,可以使用上面test方法来测试。

为啥要分两种,有啥区别?

立即加载(饿汉):如果加载的东西很大怎么办?一次全部加载了,暂时不使用是不是浪费内存? 延迟加载(懒汉):使用才加载。按需加载

但是真正使用一般是双重检查和枚举。

为啥不用懒汉饿汉?

假设s1是张三调用 Singleton1 s1 = Singleton1.getInstance(); s2是李四调用 Singleton1 s2 = Singleton1.getInstance(); 并且他们两个几乎同时执行代码(多线程)

问题出现了:假设张三刚刚执行到懒汉式的 if(s==null)没有new 这个时候李四进入if判断,这个时候两个都是null(线程不安全),那么会new两次 所以懒汉饿汉是在非高并发情况使用

改进

延迟加载:(双重检查————懒汉进阶)

class Singleton1{
    // 私有的静态的引用类型变量
    private static Singleton1 s;

    // 私有的构造器
    private Singleton1(){

    }

    // 公共的静态的可返回该类的实例
    public static Singleton1 getInstance(){
        if(s == null){
        //假设张三李四同时进入(需要加锁进行互斥操作————这里需要使用操作系统里面信号量机制实现。)
        synchronized(任意对象){
        //排队(比如先zs再李四)
        if(s==null){
            s = new Singleton1();
        }
        }
        }
        return s;
    }
}

🤔🤔🤔第一个if能不能不加????

语法上可以不加,但是逻辑上和经验上建议不省略。

🤔🤔🤔第一个if干嘛的????

避免等待,提高效率(假设非常多线程进来,第一个new了,后面非常多的进来,没有第一个if他们也会加锁排队,等待判断,但是实际上,他们完全不用等待,他们可以直接return的)

立即加载(枚举)

public enum Singleton{INSTANCE;} 就一句话,枚举天生单例,缺点不能延迟加载

Singleton1 s1 = Singleton1.INSTANCE;

Singleton1 s2 = Singleton1.INSTANCE;

最后,这个模式不是只能Java使用,所有语言都能的,我看百度大部分是java解答

好的,大家快去试试吧!

65938B3EAC871B2172C0F09BD0420627.jpg