美文网首页
单例模式

单例模式

作者: 贾里 | 来源:发表于2017-07-26 21:42 被阅读104次

    单例模式是为了让减少某个对象因为多次使用而反复创建,第一次调用singleton类时,会新建出singleton对象,但之后访问时,返回的是第一次新建的instance。
    注意:
    事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。

    1.饿汉模式

    public class SingleEasy {
        private static SingleEasy singleEasy=new SingleEasy();
    }
    

    缺点:第一步加载class文件就已经实例化了,没有做到想用时才实例化
    优点:类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

    2.懒汉模式:

    在第一次调用的时候实例化自己,每次调用getInstance时都需要进行同步开销

    • 线程不安全
    public class Singleton {
            private Singleton() {//private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。
            }     
    
            private static Singleton single = null;
    
            //静态工厂方法   
            public static Singleton getInstance() {
                if (single == null) {
                    single = new Singleton();
                }
                return single;
            }
        }
    

    但是这种写法的懒汉单例模式没有考虑线程安全问题,它是线程不安全的,在并发环境下很可能出现多个Singleton实例。为了保证懒汉单例模式的线程安全,可以对getInstance这个方法改造:

    • 线程安全
      (1)在getInstance方法上加同步,会消耗一些性能
    
     public class Singleton {
            private Singleton() {
            }
    
            private static Singleton single = null;
    
            public static synchronized Singleton getInstance() {
                if (single == null) {
                    single = new Singleton();
                }
                return single;
            }
        }
    

    (2)双重检查锁定

    public class Singleton {
            private Singleton() {
            }
    
            private static Singleton single = null;
    
            public static Singleton getInstance() {
                if (singleton == null) {
                    synchronized (Singleton.class) {
                        if (singleton == null) {
                            singleton = new Singleton();
                        }
                    }
                }
                return singleton;
            }
        }
    

    (3)静态内部类
    这种比上面1、2都好一些,既实现了线程安全,又避免了同步带来的性能影响。

    public class Singleton {    
        private static class LazyHolder {    
           private static final Singleton INSTANCE = new Singleton();    
        }    
        private Singleton (){}    
        public static final Singleton getInstance() {    
           return LazyHolder.INSTANCE;    
        }    
    }  
    

    3.DCL单例模式(双检查模式):

    基本是线程安全的,
    volatile:同步指令集,防止乱序,JDK5之后支持多并发制定集

    public class DCLSingle {
            private volatile static DCLSingle instance;
    
            public static DCLSingle getInstance() {
                if (instace == null) {
                    synchronized (DCLSingle.class) {
                        if (instance == null) {
                            instance = new DCLSingle();
                        }
                    }
                }
                return instace;
            }
    }
    

    class文件中方法的字节码流就是由JVM的指令序列构成的
    Jdk5 以后支持处理器乱序执行 汇编指令
    导致 指向地址和实例化堆区 顺序不同

    JVM调用方法的底层机制:
    第一步:提取Client.class字节码文件放到方法区,在常量池有一个DCLSigle的符号引用(这个引用没有指向真正类信息的地址)
    第二步:运行到讲DCLsingle.class字节码信息加载到内存,这时DCLSingle的符号变量指向Class类信息
    第三步:声明DCLsigle类型,sigle变量,指向DCLSigle内存空间
    第四部:在堆区开辟空间,实例化DCLSigle对象。

    Java虚拟机.png

    4.枚举:

    (1)枚举中的属性必须放在最前面
    (2)枚举中可以和java类一样定义方法
    (3)枚举中的构造方法必须是私有的

    通过一个java类来模拟枚举的功能:

    public  enum EnumManager {
        SDCardManager(10)
        {   
            @Override
            public EnumManager getSingle() {
                return SDCardManager;
            }
        }
        ,
        HttpManager(1) {
            @Override
            public EnumManager getSingle() {
                return null;
            }
        };
        public SdCardImpl getSingleton()
        {
            return new SdCardImpl();
        }
        
        
        public abstract EnumManager getSingle();
        private  EnumManager(int type)
        {
            
        }
    }
    

    相关文章

      网友评论

          本文标题:单例模式

          本文链接:https://www.haomeiwen.com/subject/llookxtx.html