单例模式

1.单例模式的优点:避免多次使用对象的频繁创建,撤销。
2.几种单例模式
<1>懒汉式,比较懒,最后new实例

package com.java.单例模式;
/** 
 * @author wangpei 
 * @version 创建时间:2017年8月18日 下午11:22:41 
 * 懒汉式
 */
public class Main {
    private static Main main;
    private Main(){}
    public synchronized static Main getInstance(){
        if(main==null)
            main=new Main();
        return main;
    }

}

2.饿汉式,因为比较饿了,所以得快点创建。

package com.java.单例模式;
/** 
 * @author wangpei 
 * @version 创建时间:2017年8月18日 下午11:25:14 
 * 饿汉式
 */
public class Main2 {
    private static final Main2 main=new Main2();
    private Main2(){}
    public synchronized static Main2 getInstance(){
        return main;

    }

}

3.双重检验锁

package com.java.单例模式;
/** 
 * @author wangpei 
 * @version 创建时间:2017年8月18日 下午11:27:05 
 * 双重检验锁
 */
public class Main3 {
    private static volatile Main3 main;
    private Main3(){}
    public static Main3 getInstance(){
        if(main==null){
            synchronized(Main3.class){
                if(main==null)
                    main=new Main3();
            }

        }
        return main;
    }

}

第一层检验:当main不为null时,直接返回结果
第二层检验:当线程A,线程B均判断main==null,线程A获得类锁,进入,创建对象,释放锁,线程B得到锁,若没有判断main==null,则其会再new一个。
加入volatile修饰的原因:
达到多线程访问时的可见性。
线程A正在执行new Main3(),而线程B判断main!=null,可能得到一个初始化未完成的main对象。添加volatile,可以保证先行发生规则,write优先于读,所以,A写完,B才读。
双重校验锁在安全方面还是不够,例如可以通过java反射,序列化,反序列化实现创建实例。

4.枚举类型实现
enum结构不能够作为子类继承其他类,但是可以用来实现接口。此外,enum类也不能够被继承,在反编译中,我们会发现该类是final的。其次,enum有且仅有private的构造器,防止外部的额外构造,

package com.java.单例模式;

/**
 * @author wangpei
 * @version 创建时间:2017年8月18日 下午11:45:44 枚举类型实现单例模式
 */
public enum Main4 {
    INSTANCE;
    public void doSomething() {
        System.out.println("hello");

    }

}

分析:对于序列化和反序列化,因为每一个枚举类型和枚举变量在JVM中都是唯一的,即Java在序列化和反序列化枚举时做了特殊的规定,枚举的writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法是被编译器禁用的,因此也不存在实现序列化接口后调用readObject会破坏单例的问题。

对于线程安全方面,类似于普通的饿汉模式,通过在第一次调用时的静态初始化创建的对象是线程安全的。

原文地址:https://www.cnblogs.com/wangxiaopei/p/8551262.html