设计模式之创建者模式-单例模式

设计模式之创建者模式-单例模式

单例模式的演变与最终合适的创建单例模式的方法

1.饿汉式:见名知意,已经迫不及待了,在项目初始化的时候就要创建出来这个单实例,这种创建方式,线程安全,但是创建时机过早,哪怕我不用实例都要创建;

/**
 1. @author pozhang
 */
public class SingletonClass {

    private static SingletonClass singleton=new SingletonClass();
    
    public static SingletonClass getInstance(){
        return singleton;
    }
}

2.懒汉式:与饿汉式相反,懒得弄,我需要的时候再创建,不需要不创建,什么时候需要呢?这样吧,就在获取的时候是偷懒最长的时候,哈哈

2.1.对于新手可能的操作,这种存在线程安全问题 ,多线程无法保证单实例,那好,我们在方法上加上synchronized或者用synchronized静态代码块全部包裹住 ,这样可以吗?可以,但是效率低下(相对后面的方式来说 ,hiahia),该怎么样呢,请看2.2

/**
 * @author pozhang
 */
public class SingletonClass {

    private static SingletonClass singleton = null;

    public static SingletonClass getInstance() {
        if (singleton == null) {
            singleton = new SingletonClass();
        }
        return singleton;
    }
}

2.2 使用下面的代码只需要第一次实例化的时候保证线程安全就可以了,其他时候直接获取,不会产生线程安全问题,大家注意看,这里实例singleton==null判断了两次,这种锁外锁内两次判断的操作,被称为双重检查锁机制,这是因为什么,假设现在两个线程同时到达第一个判断为null,此时第一个线程进入代码块实例化成功,此时如果没有第二个判断,那么实例会再次实例化,对象确实还是只有一个实例,但是对象变了,也违反单实例的定义,所以静态代码块 也需要再次判空操作(这里volatile 的作用是 为了防止指令重排,写要优先于读执行,java1.5之前是没有这种操作的,java1.5之前这种创建依然不安全,一个线程可看到 另一个线程初始化一半的实例 )

/**
 * @author pozhang
 */
public class SingletonClass {

    private static volatile SingletonClass singleton=null;

    public static SingletonClass getInstance(){
        if (singleton==null){
            synchronized (SingletonClass.class){
                if (singleton==null){
                    singleton=new SingletonClass();
                }
            }
        }
        return singleton;
    }
}

3.静态持有者模式:通过静态内部类的方式实现单例模式是线程安全的,同时静态内部类不会在Singleton类加载时就加载,而是在调用getInstance()方法时才进行加载,达到了懒加载的效果。

/**
 * @author pozhang
 */
public class SingletonClass {

   private static class SingletonClassHolder{
       private static SingletonClass singleton=new SingletonClass();
   }
   
   public static SingletonClass getInstance(){
       return SingletonClassHolder.singleton;
   }
}

静态内部类看起来已经是最完美的方法了,其实不是,可能还存在反射攻击或者反序列化攻击,但是一般应该没人这么干:

Singleton singleton = Singleton.getInstance();
    Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
    constructor.setAccessible(true);
    Singleton newSingleton = constructor.newInstance();
    System.out.println(singleton == newSingleton);

运行结果,读者可自己试下,结果 为false,这样的话,这种方式也不是什么最好的操作 ;
4.最终方案:最佳的单例实现模式就是枚举模式。利用枚举的特性,让JVM来帮我们保证线程安全和单一实例的问题,而且写法超级简单:

/**
 * @author pozhang
 */
public enum SingletonClass {

    INSTANSE;

    public static SingletonClass getInstance() {
        return INSTANSE;
    }
}

至此,单例模式讨论到此结束

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值