八种方式的单例模式(奥利给!)

什么是单例模式

简单的说就是同一个类创建的n个对象时是需要花费大量的空间,此时我们可以用单例模式解决空间浪费的情况,保证每次创建的对象是同一个对象,减少n个对空间的开销。

八种创建单例的方式

  • 饿汉式(静态常量)
  • 饿汉式(静态代码块)
  • 懒汉式(线程不安全)
  • 懒汉式(线程安全,同步方法)
  • 懒汉式(线程安全,同步代码块)
  • 双重检查
  • 静态内部类
  • 枚举

饿汉式(静态常量)

class Singleton {


// 构造器私有化
private Singleton() {
}


//创建对象实例
private final static Singleton instance = new Singleton();


//静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
}

这种单例模式优点是使用简单,线程安全,而最典型的缺点是没有懒加载,即在使用时创建对象,而是在类加载的时候实例化,这样会导致一直没有使用对象的情况下从而导致空间的浪费。

饿汉式(静态代码块)

class Singleton {
//创建对象实例
private	static Singleton instance;

//构造器私有化
private Singleton() {


}

//  静态代码块
static { 
instance = new Singleton();
}

//静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}


}


这种单例模式与上面静态常量的实现类似。

懒汉式(线程不安全)

class Singleton {
private static Singleton instance;


private Singleton() {}


//静态方法,当使用到该方法时才创建
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}

这种单例模式弥补了静态常量或者静态代码块没有懒加载的不足,它会在调用getInstance方式的时候创建对象,但是这种模式只能在单线程下使用,当一个线程进入if(instance == null)判断还没来得急创建对象,而另外一个线程抢占先机进入判断语句里从而执行创建对象语句,导致两个线程创建的对象不是同一个对象,这样就造成了线程安全问题的存在,所以这种模式是不能在多线程模式下创建的。

懒汉式(线程安全,同步方法)

class Singleton {
private static Singleton instance;


private Singleton() {}


//静态方法,加入同步方法,解决线程安全问题
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}

此单例模式即保证了线程安全问题又达到了懒加载效果,由于每次调用方法都需要同步,造成了执行效率低的问题出现,实际上当引用为空时,创建一次对象后,后面再调用方法都不需要同步,即在创建对象时同步,后续都不需要同步直接return,返回对象。

懒汉式(线程安全,同步代码块)

class Singleton {
private static Singleton instance;


private Singleton() {}


//静态方法,加入同步方法,解决线程安全问题
public static Singleton getInstance() {
if(instance == null) {
//同步代码块
synchronized (Singleton.class{
instance = new Singleton();
}
}
return instance;
}
}

这种单例模式与上面懒汉式的同步方法类似。

双重检查实现单例(推荐使用)

class Singleton {
//volatile 1.将数据直接加入到主存中对其他类可见 2. 防止指令重排
private static volatile Singleton instance;


private Singleton() {}


//加入双重检查,解决线程安全问题
public static Singleton getInstance() {
//第一次判断
if(instance == null) {
synchronized (Singleton.class) {
//第二次判断
if(instance == null) {
instance = new Singleton();
}
}

}
return instance;
 }
  }

这种单例模式解决了线程安全、懒加载,同时也解决了上面的执行效率低的问题,使用了两次判断,instance引用为空时,则创建对象,当再一次调用时通过第一次判读为false而直接返回对象,而不需要每次都同步方法带来的效率低的问题,此种方法也是实际开发中常用单例模式之一。

静态内部类实现单例(推荐使用)

class Singleton {
private static volatile Singleton instance;


//构造器私有化
private Singleton() {}


//静态内部类
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}


//返回静态内部类中的实例对象
public static synchronized Singleton getInstance() {


return SingletonInstance.INSTANCE;
}
}

这种单例模式并不是一开始就实例化,而是在getInstance()方法被调用的时候才被类加载并初始化,进而达到懒加载,由于是在类加载的时候进行初始化,此时也保证了其他线程不能进入,线程安全也得到解决,此种方法也是实际开发中常用单例模式之一。

枚举实现单例(推荐使用)

enum Singleton {
INSTANCE; //属性

}

枚举模式实现测试:

class SingletonTest{
    public static void main(String[] args) {
        //枚举创建两个单例
        Singleton2  s=Singleton2.INSTANCT;
        Singleton2  s1=Singleton2.INSTANCT;
        //判断是否同一个对象
        System.out.println(s==s1); //结果: true
    }
}

枚举实现单例不仅能避免多线程同步问题,而且还能防止反序列化重新创建
新的对象,此种方法也是实际开发中常用单例模式之一。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值