设计模式之单例模式的7种实现方式

本节目标

1.至少能手写单例模式中饿汉式和双检锁
2.了解线程安全的单例模式

什么是单例?

单例类在整个程序中只能有一个实例,这个类负责创建自己的对象,并确保只有一个对象被创建。

代码实现要点
a) 私有构造器
b) 持有该类的属性
c) 对外提供获取实例的静态方法

(面试可手写)
饿汉式:线程安全、反射不安全、反序列化不安全

public class Singleton1 implements Serializable {
    private static Singleton1 singleton1=new Singleton1();

    private Singleton1() {}

    public static Singleton1 getInstance() {
        return singleton1;
    }

    private Object readResolve() {
        return singleton1;
    }
}

登记式:(静态内部类):线程安全、防止反射攻击、反序列化不安全

public class Singleton2 {

    private static class SingletonHolder {
        private static Singleton2 singleton2=new Singleton2();
    }

    private Singleton2() {
        System.out.println("Singleton2 loaded");
        if (SingletonHolder.singleton2 != null) {
            throw new IllegalStateException();
        }
    }

    public static Singleton2 getInstance() {
        return SingletonHolder.singleton2;
    }
}

枚举式:线程安全、支持序列化、反序列化安全、防止反射攻击

public enum Singleton3 {
    INSTANCE{
        @Override
        protected void doSomething() {
            System.out.println("method doSomething start...");
        }
    };

    protected abstract void doSomething();

}

懒汉式:线程不安全、延迟加载、(两种加同步,效率低)一种是synchronized代码块一种是synchronized修饰方法

public class Singleton4 {
    private static Singleton4 instance = null;

    private Singleton4() {
    }

    public static Singleton4 getInstance() {
        if (instance == null) {
            instance = new Singleton4();
        }
        return instance;
    }
}

(面试可手写)
双检锁:线程安全、volatile

public class Singleton7 {
    private static volatile Singleton7 instance = null;

    private Singleton7() {
    }

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

################
instance=new Singleton7()会执行如下操作:
(1) 分配对象内存空间
(2) 初始化对象
(3) instance指向(1)中分配的空间
在某些编译器上,可能出现指令重排:
(1) 分配对象内存空间
(2) instance指向(1)中分配的空间 (但此时对象没有初始化)
(3) 初始化对象
##################

(面试加分项)
ThreadLocal:不加锁,以空间换时间,为每个线程提供变量的独立副本,可以保证各自线程中是单例的,但是不同线程之间不保证

public class Singleton8 {
    private static Singleton8 instance = null;

    private Singleton8() { }

    private static final ThreadLocal<Singleton8> threadLocalSingleton = new ThreadLocal<Singleton8>() {
        @Override
        protected Singleton8 initialValue() {
            return new Singleton8();
        }
    };

    public static Singleton8 getInstance() {
        return threadLocalSingleton.get();
    }
}

(面试加分项)
CAS:无锁乐观策略,线程安全

扫描二维码关注公众号,回复: 10033495 查看本文章
public class Singleton9 {
    private static final AtomicReference<Singleton9> instance = new AtomicReference<>();

    private Singleton9() {
        System.out.println("Singleton9 Loaded");
    }

    public static final Singleton9 getInstance() {
        for (; ; ) {
            Singleton9 current = instance.get();
            if (current != null) {
                return current;
            }
            current = new Singleton9();
            if (instance.compareAndSet(null, current)) {
                return current;
            }
        }
    }
}
发布了28 篇原创文章 · 获赞 11 · 访问量 6586

猜你喜欢

转载自blog.csdn.net/zhanxiaozhangA/article/details/105008727