单例模式

2018-11-20  本文已影响0人  KingdomCoder

定义:

保证一个类只有一个实例,并提供一个全局访问点。(创建型)

应用场景:

想确保任何情况下都绝对只有一个实例。

优点:

1.在内存只有一个实例,减少内存开销。
2.可以避免对资源的多重占用。
3.设置了全局的访问点,严格的控制访问

缺点:

没有接口,扩展比较困难,只能修改代码

重点:

1.私有构造器
2.线程安全
3.延迟加载
4.序列化和反序列化得安全
5.反射,防御反射攻击

Coding:

1.懒汉式(线程不安全):

public class LazySingleton {

    private static  LazySingleton instance = null;

    private LazySingleton(){

    }
    /**
     *  多线程不安全的
     * @return
     */
    public static  LazySingleton getInstance(){
        if(null == instance){
            return new LazySingleton();
        }
        return instance;
    }
}

2.懒汉式改进(通过加锁保证线程安全):

public class LazySynchronizedSingleton {
    private static LazySynchronizedSingleton instance = null;
    private LazySynchronizedSingleton() {

    }
    /**
     * 改进方式--同步锁,多线程安全的(但是性能比较差)
     *
     * @return
     */
    public synchronized static LazySynchronizedSingleton getInstance1() {
        if (null == instance) {
            return new LazySynchronizedSingleton();
        }
        return instance;
    }
}

3.双重检测(线程不安全):

/**
 * 双重检测
 */
public class LazyDoubleCheckSingleton {
    private static LazyDoubleCheckSingleton instance = null;
    private LazyDoubleCheckSingleton(){

    }
    /**
     *  此种方法存在弊端
     * @return
     */
    public static  LazyDoubleCheckSingleton getInstance(){
        if(null == instance){
            synchronized (instance) {
                if(null == instance){
                    /**
                     * 1.给对象分配内存
                     * 2.初始化对象
                     * 3.设置instance 指向分配的内存地址
                     * 此处存在指令重排序的问题: 3可能在2之前执行
                     */
                    new LazyDoubleCheckSingleton();
                }
            }
            return instance;
        }
        return instance;
    }
}
双重检测单例分析

分析:
线程0还没初始化对象时,线程1判断对象部位null,线程1可能会直接访问未初始化完成的对象,可能会导致异常。
4.双重检测改进(volatile 保证线程可见性):

/**
 * 双重检测
 */
public class LazyDoubleCheckSingleton {
    //线程可见,防止指令重排序
    private volatile static LazyDoubleCheckSingleton instance = null;

    private LazyDoubleCheckSingleton(){

    }
    /**
     *  此种方法存在弊端
     * @return
     */
    public static  LazyDoubleCheckSingleton getInstance(){
        if(null == instance){
            synchronized (instance) {
                if(null == instance){
                    /**
                     * 1.给对象分配内存
                     * 2.初始化对象
                     * 3.设置instance 指向分配的内存地址
                     * 此处存在指令重排序的问题: 3可能在2之前执行
                     */
                    new LazyDoubleCheckSingleton();
                }
            }
            return instance;
        }
        return instance;
    }
}

5.静态内部类-单例(利用类的初始化):

/**
 * 静态内部类创建单例对象
 */
public class StaticInnerClassSingleton {
    /**
     * 静态内部类
     */
    private static class InnerClass {
        private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
    }

    public static StaticInnerClassSingleton getInstance(){
        return InnerClass.staticInnerClassSingleton;
    }

    private StaticInnerClassSingleton(){

    }
}

6.饿汉式:

/**
 * 饿汉式--类加载的时候就初始化好了
 */
public class HungrySignleton {

    private HungrySignleton(){

    }

    private static final HungrySignleton INSTANCE = new HungrySignleton();

    public static HungrySignleton getInstance(){
        return INSTANCE;
    }
}
微信公众号欢迎关注.jpg
上一篇 下一篇

猜你喜欢

热点阅读