【设计模式】单例模式——004

单例模式

简介

定义

  • 单例模式是创建型模式。
  • 单例模式只涉及到一个单一的类,只负责创建自己的对象,同时确保只有单个对象被创建。(单例类必须自己创建自己的唯一实例。)
  • 这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。(单例类必须给所有其他对象提供这一实例。)
  • 有多种实现方式,懒汉式,饿汉式等等。

好处

  1. 单例模式能避免对资源的多重占用。
  2. 由于只创建了一个实例,减少了内存的开销。

缺点

  1. 没有接口,不能继承
  2. 与单一职责原则冲突
  3. 一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

实例

创建一个SIngleton类

创建一个SingleObject对象,确保只有单个对象被创建。
构造方法使用private使SingleObject类避免被实例化。
getInstance方法提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

//Singleton.java
public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
    public void showMessage(){
        System.out.println("This is Singleton one.");
    }
}

从 singleton 类获取唯一的对象

注意,这里由于之前创建对象时法使用private使SingleObject类避免被实例化,所以不能使用Singleton object = new Singleton();,而应该使用getInstance方法

//SingletonPatternDemo.java
public class SingletonPatternDemo {
    public static void main(String[] args) {
        Singleton object =Singleton.getInstance();
        object.showMessage();
    }
}

运行结果
在这里插入图片描述

懒汉式

如果没有对象就创建,有就直接用
线程不安全,不支持多线程的懒汉式(未加锁)

public class LazySingleton {
    private static LazySingleton instance;
    private LazySingleton(){}
    public static LazySingleton getInstance(){
        if(instance==null){
            instance = new LazySingleton();
        }
        return instance;
    }
}

线程安全,支持多线程的懒汉式

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

饿汉式

类加载时就初始化对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。

public class HungrySingleton {
    private static HungrySingleton instance = new HungrySingleton();
    
    private HungrySingleton (){}
    
    public static HungrySingleton getInstance() {
        return instance;
    }
}

懒汉式与饿汉式的根本区别在与是否在类内方法外创建自己的对象。 并且声明对象都需要私有化,构造方法都要私有化,这样外部才不能通过 new
对象的方式来访问。 饿汉式的话是声明并创建对象(因为他饿),懒汉式的话只是声明对象,在调用该类的 getinstance() 方法时才会进行
new 对象。

双重校验锁式double-checked locking

采用双锁机制,安全且在多线程情况下能保持高性能。
getInstance() 的性能对应用程序很关键。

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

登记式/静态内部类

对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
这种方式同样利用了 classloader 机制来保证初始化 instance 时只有一个线程

它跟第 3 种方式不同的是:第 3 种方式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy> loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder> 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化> instance。

public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
    return SingletonHolder.INSTANCE;  
    }  
}

枚举

简洁,自动支持序列化机制,绝对防止多次实例化

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}

总结

不推荐使用懒汉式,通常情况使用饿汉式,只有在要明确实现 lazy loading 效果时,才会使用登记式。如果涉及到反序列化创建对象时,可以尝试使用枚举方式。如果有其他特殊的需求,可以考虑使用双检锁方式。

关注博主,一起来学习设计模式吧
请添加图片描述

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

疼疼蛇

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

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

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

打赏作者

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

抵扣说明:

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

余额充值