java设计模式-单例模式

来源:互联网 发布:知乎 武侠 编辑:程序博客网 时间:2024/06/17 09:20

单例模式:饿汉模式以及懒模式

饿汉模式:线程安全,不会产生多个实例。但如果加载耗时,增加项目初始化时间,如果在运行过程中,没有用到,可能增加空间的浪费

懒汉模式:充分利用资源,实现懒加载策略。(可能线程不安全,需要用户自己优化)


例子

饿汉模式

/** * Description:饿汉模式 * User: lc * Date: 2017/9/30 0030 * Time: 下午 3:52 */public class HungrySingleton {    /**     * 利用classLoader加载     */    private static final HungrySingleton hungrySingleton = new HungrySingleton();    /**     * 私有的构造函数:不让外界创建     */    private HungrySingleton() {    }//提供唯一对外,反射除外    public static HungrySingleton getInstance() {        return hungrySingleton;    }}

懒汉模式:几种变形


1.不加任何修饰(不安全

/** * Description:懒汉模式 * User: lc * Date: 2017/9/30 0030 * Time: 下午 3:58 */public class LazySingleton {    /**     * 未初始化     */    private static LazySingleton instance;    private LazySingleton() {    }    public static LazySingleton getInstance() {        //第一次调用会初始化.不过多线程情况下,会重复初始化(线程安全问题)        if (instance == null) instance = new LazySingleton();        return instance;    }}


2.synchronized(不安全

/** * Description:懒汉模式 * User: lc * Date: 2017/9/30 0030 * Time: 下午 3:58 */public class LazySingleton1 {    /**     * 未初始化     */    private static LazySingleton1 instance;    private LazySingleton1() {    }    public static LazySingleton1 getInstance() {        if (instance == null) {            //但是如果线程A和B同时执行到了Synchronized(singleton.class),            // 虽然也是只有一个线程能够执行,假如线程B先执行,线程B获得锁,线程B执行完之后,线程A获得锁,            // 但是此时没有检查singleton是否为空就直接执行了,所以还会出现两个singleton实例的情况            synchronized(LazySingleton1.class)            {                instance = new LazySingleton1();            }        }        return instance;    }}

2.synchronized以及判断是否NULL(不安全

/** * Description:懒汉模式:双重检查 * User: lc * Date: 2017/9/30 0030 * Time: 下午 3:58 */public class LazySingleton2 {    /**     * 要volatile修饰     * 理由:比如2个线程A/B线程。     */    private  static LazySingleton2 instance;    private LazySingleton2() {    }    public static LazySingleton2 getInstance() {        if (instance == null) {            synchronized (LazySingleton2.class) {                if(instance == null)                    //此处还是有问题:虽然做了双重判断。 因为 newLazySingleTon1()是非原子操作                    //  A a=new A()                    //  进行了三步操作:1.申请空间2.将引用指向该空间地址3.初始化构造                    //在理想情况下,按照1->3->2的步骤执行时,双检锁形式可以正常工作,但是由于Java内存模型,允许重排序,所以                    //完全可能按照1->2->3的顺序执行,则导致双检锁形式出现问题。即线程1在执行single=new Singleton()语句时,刚好按照1->2->3的顺序                     //执行到step2处,此时,instance指向mem内存区域,而该内存区域未被初始化;同时,线程2在第一个if(instance==null)地方发现instan                     // ce不为null了,于是得到这个为被初始化的实例instance进行使用,导致错误。
                    //synchronized:允许修饰的对象,可见性,但是可以允许jvm的进行重排序                    instance = new LazySingleton2();                return instance;            }        }        return instance;    }}


3.加synchronized以及volatile(安全)

/** * Description:懒汉模式:双重检查 * User: lc * Date: 2017/9/30 0030 * Time: 下午 3:58 */public class LazySingleton2 {    /**     * 要volatile修饰     * 理由:比如2个线程A/B线程。     */    private volatile static LazySingleton2 instance;    private LazySingleton2() {    }    public static LazySingleton2 getInstance() {        if (instance == null) {            synchronized (LazySingleton2.class) {                if (instance == null)                    instance = new LazySingleton2();            }        }        return instance;    }}




4.静态内部类(安全)

/** * Description:懒汉模式: * User: lc * Date: 2017/9/30 0030 * Time: 下午 3:58 */public class StaticLazySingleton {    /**     *     *1.私有内部类,外部不知道该类的存在     * 2.外部类初始化的时候,该内部类还没加载,只有通过第一次调用才(比如这个例子:触发getInstance())加载,加载是利用jvm加载,而jvm加载某个类,只能加载一次,所以是只能有一个class类。故线程安全     * 3.对外提供唯一的出口     *     */    private StaticLazySingleton() {    }   // 静态内部类    private static class StaticLazySingletonInstance    {        private static final StaticLazySingleton staticLazySingleton = new StaticLazySingleton();    }    public static StaticLazySingleton getInstance() {        return StaticLazySingletonInstance.staticLazySingleton;    }}


原创粉丝点击