你真的会手写单例吗?

你真的会手写单例吗?

概述

今天在刷牛客看面经的时候遇到手写单例的面试题,本来以为这是一件很简单的事情,但是真的当我准备写的时候一时竟让不知道从何写起,平时很少注意到这些细节。所以,在经过学习之后将其总结成这篇文章

在动手写之前我们首先得明确这三件事:

  1. 什么是单例
  2. 单例模式的类需要满足什么条件
  3. 什么是懒汉式?什么是饿汉式?

我们一个一个问题逐步来分析,单例模式我这里不做详细介绍,其大概的意思就是全局只有这一个类。

既然如此,要满足全局只有这一个类,那么我们首先需要想到构造器私有,这样,其他的类就不能创建该类了

既然构造器已经私有,那么我们还需要提供一个公共的方法供其他类调用,因此,单例对象的创建只能由其本身来创建,并且,还需要向外提供一个接口以供其他类获取到这个单例对象

然后又根据单例对象的创建时机的不同分为懒汉式和饿汉式:当程序刚启动时就创建这个单例对象就是饿汉式,仅当外部对象第一次访问该接口,获取单例对象时才创建就是懒汉式

OK,基本的概念我已经介绍完毕了,那么我们来看看手写单例的六种方式吧。

饿汉式——静态代码块

/**
 * @author Pymjl
 * @version 1.0
 * @date 2022/8/11 0:17
 **/
public class HungrySingletonObject {
    
    
    private static HungrySingletonObject singleton;

    private HungrySingletonObject() {
    
    
        
    }

    static {
    
    
        singleton = new HungrySingletonObject();
    }

    public static HungrySingletonObject getInstance() {
    
    
        return singleton;
    }
}

饿汉式——静态常量

/**
 * 饿汉式单例,线程安全
 *
 * @author Pymjl
 * @version 1.0
 * @date 2022/8/10 20:17
 **/
public class HungrySingleton {
    
    
    private static HungrySingleton instance = new HungrySingleton();

    private HungrySingleton() {
    
    
    }

    public static HungrySingleton getInstance() {
    
    
        return instance;
    }
}

懒汉式——线程不安全

package singleton;

/**
 * 懒汉式单例,线程不安全
 *
 * @author Pymjl
 * @version 1.0
 * @date 2022/8/11 0:22
 **/
public class Singleton {
    
    
    private static Singleton singleton;

    private Singleton() {
    
    

    }

    public static Singleton getInstance() {
    
    
        //在多线程环境下,加入线程A、B、C都执行到if语句后用完了时间片,
        //此时因为singleton还未被初始化,那么这三个线程判断都为true
        //当重新获取时间片后这三个线程会分别创建一个singleton对象,因此线程不安全
        if (singleton == null) {
    
    
            singleton = new Singleton();
        }
        return singleton;
    }
}

懒汉式——线程安全

/**
 * 既然上面的写法线程不安全,那么我们很自然而然的想到对该方法进行加锁
 *
 * @author Pymjl
 * @version 1.0
 * @date 2022/8/10 20:27
 **/
public class LazySingletonObject {
    
    
    private static LazySingletonObject singleton;

    private LazySingletonObject() {
    
    

    }

    /**
     * 该种方式效率会有折损,没有双重检查效率高
     *
     * @return {@code LazySingletonObject}
     */
    public synchronized static LazySingletonObject getInstance() {
    
    
        if (singleton == null) {
    
    
            singleton = new LazySingletonObject();
        }
        return singleton;
    }
}

懒汉式——双重检查

/**
 * 懒汉式单例,双重检查,线程安全
 *
 * @author Pymjl
 * @version 1.0
 * @date 2022/8/10 20:09
 **/
public class LazySingleton {
    
    
    /**
     * 注意,这里一定要使用volatile关键字来修饰,保证singleton对其他线程的可见性
     * 以及防止指令重排(保证有序性)
     * 如果不添加该关键字,可能会在多线程环境下某个线程获取到还未被初始化的对象
     */
    private volatile static LazySingleton singleton;

    private LazySingleton() {
    
    

    }

    /**
     * 获得实例,双重检查
     *
     * @return {@code LazySingleton}
     */
    public static LazySingleton getInstance() {
    
    
        if (singleton == null) {
    
    
            //如果为null则竞争锁
            synchronized (LazySingleton.class) {
    
    
                //此时需要进行双重检查,防止其他线程在竞争到锁之后时间片用完,
                //再次被唤醒获取锁之后重复创建对象
                if (singleton == null) {
    
    
                    singleton = new LazySingleton();
                }
            }
        }
        return singleton;
    }
}

懒汉式——静态内部类

/**
 * 懒汉式单例,采用静态内部类的方法
 *
 * @author Pymjl
 * @version 1.0
 * @date 2022/8/10 20:22
 **/
public class Singleton {
    
    
    private static class SingletonHolder {
    
    
        //必须保证被static和final修饰
        private static final Singleton INSTANCE = new Singleton();
    }

    private Singleton() {
    
    
    }

    public static Singleton getInstance() {
    
    
        //这里也是懒汉式的加载,因为只有SingletonHolder类被主动使用之后才会被加载
        //即只有当显示的调用getInstance()方法时才会初始化instance
        return SingletonHolder.INSTANCE;
    }
}

好啦,掌握这几种手写单例模式的方法面试基本上都不会有问题了,感谢大家的观看,我们下次再见

猜你喜欢

转载自blog.csdn.net/apple_52109766/article/details/126277144