设计模式之单例模式

       📝个人主页:五敷有你      

 🔥系列专栏:设计模式

⛺️稳中求进,晒太阳

单例模式

单例模式属于创建者模式,是Java中最简单的设计模式之一,这种设计模式属于创建型模式,提供了一种创建对象的最佳方式。

该模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。

注意:

  1. 单例只能有一个实例。

  2. 单例类必须自己创建自己的唯一实例

  3. 单例类必须给所有其他对象提供这一实例。

优点:

  1. 内存中只有一个实例,减少内存开销,尤其是频繁创建和销毁实例时。

  2. 避免资源的多重占用。

缺点:

  1. 没有接口,不能继承。

  2. 与单一职责冲突,一个类应该只关心内部逻辑,而不关心实力化方式。

饿汉式

饿汉式:直接创建出类的实例化,然后用private私有化,对外只用静态方法暴露。

静态变量

步骤

  1. 构造器私有化

  2. 类的内部创建对象

  3. 向外暴露一个静态的公共方法

优点:写法简单,在类加载的时候完成实例化,避免了线程同步的问题。

缺点:类加载完成实例化,没有达到LazyLoading的效果,若该实例从未使用,会造成内存浪费。

class Singleton {
    //私有化构造器
    private Singleton() {   
    }
    //内部创建对象实例
    private final static Singleton instance = new Singleton();
    //对外公有的静态方法
    public static Singleton getInstance() {
        return instance;
    }
}

静态代码块
public class Hungry {
    private static Hungry instance;
    static {
        instance=new Hungry();
    }
    private Hungry(){};
    public static Hungry getInstance(){
        return instance;
    }
​
​
}

懒汉式

所谓懒汉式,就是在需要调用的时候再创建类的实例化。

线程不安全

起到了懒加载效果,但是只能在单线程使用,多线程会不安全,因为当多个线程并发同时判断instance为空时,就会相应的实例化多个对象。

/**
 * 线程不安全
 */
public class LazyLoadMode {
    private static LazyLoadMode instance;
    
    private LazyLoadMode(){};
    public static LazyLoadMode getInstance(){
        if(instance==null){
            instance=new LazyLoadMode();
        }
        return instance;
    }
}

如下:线程不安全。

线程安全

不安全加个锁不就安全了,使用synchronized关键字。

这样虽然解决了线程安全,但其实实例化操作只做一次,而获取实例(即getInstance)的操作是很多次的,把调用的方法加上同步,会大大降低效率。

每次都会加锁解锁,效率太低了。

/**
 * 线程不安全
 */
public class LazyLoadMode {
    private static LazyLoadMode instance;
​
    private LazyLoadMode(){};
    public static synchronized LazyLoadMode getInstance(){
        if(instance==null){
            instance=new LazyLoadMode();
        }
        return instance;
    }
}

双重检查

上面代码效率低,那在同步前判断一下有没有实例化不就好了,没有实例化就new一个,否则直接return即可。

需要使用volatile,防止指令重排序,如果不用volatile,就会和线程不安全情形一样,在if判断那会有并发,导致new了多个实例化。。

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;  //否则直接return
    }  
}

这样既实现了懒加载,又保证了线程安全。

静态内部类

静态内部类在外部类装载时不会实例化,当调用的时候才会装载并实例化且JVM保证了其装载时的线程安全性。也能保证懒加载和线程安全,有点像自带版的双重检查。

class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}
    //静态内部类,包含一个静态属性:Singleton
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton(); 
    }
    //对外公有的静态方法,直接返回SingletonInstance.INSTANCE
    public static synchronized Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

枚举

其实,使用枚举也能实现单例模式,不仅能避免多线程同步问题也能防止反序列化重新创建新的对象。

enum Singleton {
    INSTANCE; //属性
    public void say() {
        System.out.println("记得三连~");
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

五敷有你

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

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

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

打赏作者

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

抵扣说明:

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

余额充值