用单例模式代码面对面试,不断升级深入,面试最佳

 在面试时候,通常会遇到笔试,其中笔试会要求面试者手写单例模式,基本上面试者写的都是懒汉模式,也就是下面的这部分代码了,然而它并不是线程安全的,还可以优化哦,我们可以在这里给自己面试加分

**
 * 懒汉模式
 * 要保证对象只能被初始化一次,先保证这个类不能随便被new
 */
@NotThreadSafe
public class SingletomExample1 {
    //私有构造函数
    private SingletomExample1(){ }
    //单例对象
    private static SingletomExample1 instance=null;
    //静态的工厂方法
    public static SingletomExample1 getInstance(){
        //如果对线程中,在这里是不安全的
        if(instance == null){
            instance = new SingletomExample1();
        }
        return instance;
    }
}

 为什么经常写懒汉模式而不是饿汉模式呢?答案在这里 ↓


/**
 * 饿汉模式
 * 单例实例在类装载使用时进行创建
 * 饿汉模式缺点:如果构造方法中存在过多的处理,会导致这个类加载
 * 的特别慢,可能会性能下降。如果使用这个模式只是进行了类的加载的
 * 话,它就会使资源浪费。所以在使用饿汉模式时,要考虑到这个类构造处理的
 * 不是很复杂,这个构造也一定能够用到。
 */
@ThreadSafe
public class SingletomExample2 {
    //私有构造函数
    private SingletomExample2(){ }
    //单例对象
    private static SingletomExample2 instance = new SingletomExample2();
    //静态的工厂方法
    public static SingletomExample2 getInstance(){
        return instance;
    }
}

 好了,我们现在来优化上部分的懒汉模式代码吧,线程不安全,大家通常想到的是synchronized锁吧,如下面这样,但它也还不是最安全的哦

@ThreadSafe
public class SingletomExample3 {
    //私有构造函数
    private SingletomExample3(){ }
    //单例对象
    private static SingletomExample3 instance=null;
    //静态的工厂方法
    public static synchronized SingletomExample3 getInstance(){
        //如果对线程中,在这里是不安全的
        if(instance == null){
            instance = new SingletomExample3();
        }
        return instance;
    }
}

 为什么线程不是最安全的呢,那是因为有指令重排序的存在,这里我就不详解什么是指令重排序了,你们可以搜索关键字“指令重排序”、“happens-befor”去看看吧,顺便说一下synchronized,我们一般是把synchronized放在方法上面的,但是这样不好,因为会影响性能,所以你们以后在使用synchronized锁的时候,最好是放到代码块中,具体的,看下面哦

@ThreadSafe
public class SingletomExample4 {
    //私有构造函数
    private SingletomExample4(){ }
    //正常执行步骤
    //1.memory = allocate() 分配对象的内存空间
    //2、ctorInstance()初始化对象
    //3.instance = memory 设置instance指向刚分配的内存

    //JVM和CPU优化,发生了指令重排序

    //1.memory = allocate() 分配对象的内存空间
    //3.instance = memory 设置instance指向刚分配的内存
    //2、ctorInstance()初始化对象
    /**
     * 当一个线程运行到了重排序之后的第3步时,另一个线程就会发现
     * instance不再是null,就会直接返回应用了,而这个时候第一个
     * 线程还没有执行优化后的2操作,所以第二个线程就会报错。
     */
    //单例对象
    private static SingletomExample4 instance=null;
    //静态的工厂方法
    public static  SingletomExample4 getInstance(){
        //如果对线程中,在这里是不安全的
        if(instance == null){//双层检测机制
            synchronized (SingletomExample4.class) {//同步锁
                instance = new SingletomExample4();
            }
        }
        return instance;
    }
}

 那么要怎么解决指令重排序呢,这里我们要用到volatile,它主要是加入内存屏障和禁止重排序的功能。它是高并发中的关键知识哦。进行到这一步,单例模式基本上是没有再进化的可能了,加油哦

懒汉模式--双层同步锁单例模式

/**
 * 懒汉模式--双层同步锁单例模式
 * 要保证对象只能被初始化一次,先保证这个类不能随便被new
 */
@ThreadSafe
public class SingletomExample5 {
    //私有构造函数
    private SingletomExample5(){ }
    //解决方法是:用volatile来进行修饰,这样就不会发生指令重排了
    //单例对象 volatile + 双重检测机制 -》禁止指令重排
    private volatile static SingletomExample5 instance=null;
    //静态的工厂方法
    public static SingletomExample5 getInstance(){
        //如果对线程中,在这里是不安全的
        if(instance == null){//双层检测机制
            synchronized (SingletomExample5.class) {//同步锁
                instance = new SingletomExample5();
            }
        }
        return instance;
    }
}

 有了上面的优化,相信你在面试官面前一定能够为自己提高分数了吧,单例模式呢最主要的就是对象唯一的,如同古代皇帝一样,一个朝代只有一个皇帝,而上面的优化已经让我们达到了这个效果了,而且线程也是绝对安全的了。为什么下面还有代码呢,因为我发现它还可以究极进化一次,用它来实现单例模式,感觉synchronized锁什么的,都弱爆了,因为它是靠 jvm 来保证它只会被实例话一次的哦

**
 * 枚举模式:最安全的
 */
@ThreadSafe
@Recommend
public class SingletomExample7 {
    //私有构造函数
    private SingletomExample7(){ }

    //单例对象
    public static SingletomExample7 getInstance(){
        return Singleton.INSTANCE.getInstance();
    }

    private enum Singleton{
        INSTANCE;//定义一个值
        private SingletomExample7 singleton;//私有类的实例
        //JVM保证这个方法绝对只调用一次
        Singleton(){
            singleton = new SingletomExample7();
        }
        public SingletomExample7 getInstance() {
            return singleton;
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值