线程安全的单例的几种实现方法

1. 使用synchronized

饱汉:双重检查锁定饿汉静态内部类枚举 都属于利用synchronized同步原理实现

1.1 饱汉:双重检查锁定(double-checked locking)

public class SingleTon {

  // 静态实例变量加上volatile
    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;
    }

1.2 饿汉

1.3 静态内部类

以上的静态内部类、饿汉等模式均是通过定义静态的成员变量,以保证单例对象可以在类初始化的过程中被实例化。

这其实是利用了ClassLoader的线程安全机制。ClassLoader的loadClass方法在加载类的时候使用了synchronized关键字。

所以, 除非被重写,这个方法默认在整个装载过程中都是线程安全的。所以在类加载过程中对象的创建也是线程安全的。

1.4 枚举

枚举其实底层是依赖Enum类实现的,这个类的成员变量都是static类型的,并且在静态代码块中实例化的,和饿汉有点像, 所以他天然是线程安全的。

2. 利用CAS原理

3. 使用ThreadLocal

与前面的方式不同的是,ThreadLocal保证的是单个线程内部访问的是同一个实例,不同线程访问的不是同一个实例,即局部单例,并非全局单例。

序列化与反序列化破坏单例问题

序列化对象时,序列化前后得到对象不是同一个实例。解决办法就是在反序列化的过程中使用readResolve()方法,该方法在反序列化时会被调用,该方法不是接口定义的方法,有点儿约定俗成的感觉,单例实现的代码如下:

参考链接:

高并发下线程安全的单例模式(最全最经典)

单例模式——线程安全的两种实现

面试官真是搞笑!让实现线程安全的单例,又不让使用synchronized!

最后更新于

这有帮助吗?