设计模式之单例模式

单例模式,也就是创建全局唯一的对象的模式,属于创建型模式。一个类只允许创建一个对象的时候,那这个类就是单例类。
单例类有很多种实现方式,例如饿汉式,懒汉式,双重检测,当然还有Sping基于IOC的单例模式等。下面就来说一下单例模式的用法,单例模式无外乎就几个关键的地方:

  1. 构造器是私有的
  2. 是否是线程安全的
  3. 是否支持延迟构造
1、饿汉式
public class SingleDog {
    private static final SingleDog singleDog = new SingleDog();
    private SingleDog(){}

    public static SingleDog getSingleDog(){
        return singleDog;
    }
}

饿汉式的特点是,在类加载的时候就把对象创建好了。这里说明了两个问题,

  1. 没有线程安全问题。
  2. 不支持延迟加载。

有人会觉得不支持延迟加载是一个缺点,觉得可能会浪费资源。但是他有两个很重要的优点,第一点是节约调用时间,第一次调用的时候,如果初始化很长的话,可能会造成接口响应时间变长,甚至是超时。如果把初始化提前到启动的时候做的话,就不会出现这个问题了。
第二点是把异常提前到启动的时候,这个类在代码重是我们一定要创建成功的,例如ID获取器,例如Service类那些,如果没创建成功,系统就没办法使用了。这种我们就需要放在启动的时候做了。

2、懒汉式

和饿汉式相对的就是懒汉式了,先来看看实现方式:

public class SingleDog {
    private static SingleDog singleDog;
    private SingleDog(){}

    public synchronized static SingleDog getSingleDog(){
        if(singleDog == null){
            singleDog = new SingleDog();
        }
        return singleDog;
    }
}

特点就是支持延迟加载。缺点很明显,因为加了重量级锁,导致并发度很低。如果访问量不大,那还可以,如果访问量大的话,这种调用方式是不可以接受的,严重影响了性能。

3、双重检查

饿汉式不支持延迟加载,懒汉式有并发问题。接下来就介绍一种既支持延迟加载,又支持高并发的写法。双重检查,只有没创建的对象时候会加锁,有对象的时候访问不会加锁,大大减少了加锁次数。

public class SingleDog {    
    private volatile static SingleDog singleDog;
    private SingleDog(){}
    
    public static SingleDog getSingleDog(){
        if(singleDog == null){
            synchronized (SingleDog.class){
                // 双重检查,避免锁住的时候被分配对象了
                if(singleDog == null) {
                    singleDog = new SingleDog();
                }
            }
        }
        return singleDog;
    }
 }

4、静态内部类

这种方式的效果类似于双重检查,但是实现起来又比双重检查实现起来简单。充分利用了JVM的特性,JVM在初始化外部类的时候,并不会初始化内部类,在调用getInstance()的时候才会初始化内部类(可以通过静态代码块去试验一下就知道了)。

public class SingleDog {
    private SingleDog(){}
    
    private static class InnerSingleDog{
        private static final SingleDog singleDog = new SingleDog();
    }
    
    public static SingleDog getInstance(){
        return InnerSingleDog.singleDog;
    }
}

5、Spring

如果是使用Java的朋友,在工作中使用最多的应该就是Spring的单例模式了。因为构造器是public的,这种单例是需要程序员去保证单例的,获取实例的时候通过Spring的IOC去获取。

@Bean
public SingleDog singelDog(){
	return new SingeleDog();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值